APUE讀書筆記-第四章 文件和目錄
來源:程序員人生 發布時間:2016-07-07 19:29:29 閱讀次數:2521次
到第4章了,不知甚么時候才能把這本書看完,耽誤的時間太多了。
第4章是在第3章的基礎上,主要描寫文件系統的其他性質和文件的性質。
4.2 stat、fstat、fstatat、lstat函數
首先來看看這4個函數的原型:
#include <sys/stat.h> ///usr/include/x86_64-linux-gnu/sys/
int stat (const char *__restrict __file, struct stat *__restrict __buf)
int fstat (int __fd, struct stat *__buf)
int fstatat (int __fd, const char *__restrict __file, struct stat *__restrict __buf, int __flag)
int lstat (const char *__restrict __file, struct stat *__restrict __buf)
這幾個函數的功能概括起來就是:取得stat結構體。區分就在于stat函數通過文件名取得這1結構體;fstat通過文件描寫符;lstat返回該符號鏈接的有關信息,而不是由該符號鏈接援用的文件的信息;fstatat返回當前文件夾下(由fd指向)某個文件(文件名為file)的stat結構體。
好了,不管上面的幾個函數具體功能為什么,其核心都是返回stat結構體,stat定義以下:
struct stat
{
__dev_t st_dev; /* Device. */
#ifndef __x86_64__
unsigned short int __pad1;
#endif
#if defined __x86_64__ || !defined __USE_FILE_OFFSET64
__ino_t st_ino; /* File serial number. */
#else
__ino_t __st_ino; /* 32bit file serial number. */
#endif
#ifndef __x86_64__
__mode_t st_mode; /* File mode. */
__nlink_t st_nlink; /* Link count. */
#else
__nlink_t st_nlink; /* Link count. */
__mode_t st_mode; /* File mode. */
#endif
__uid_t st_uid; /* User ID of the file's owner. */
__gid_t st_gid; /* Group ID of the file's group.*/
#ifdef __x86_64__
int __pad0;
#endif
__dev_t st_rdev; /* Device number, if device. */
#ifndef __x86_64__
unsigned short int __pad2;
#endif
#if defined __x86_64__ || !defined __USE_FILE_OFFSET64
__off_t st_size; /* Size of file, in bytes. */
#else
__off64_t st_size; /* Size of file, in bytes. */
#endif
__blksize_t st_blksize; /* Optimal block size for I/O. */
#if defined __x86_64__ || !defined __USE_FILE_OFFSET64
__blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
#else
__blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
#endif
#ifdef __USE_XOPEN2K8
/* Nanosecond resolution timestamps are stored in a format
equivalent to 'struct timespec'. This is the type used
whenever possible but the Unix namespace rules do not allow the
identifier 'timespec' to appear in the <sys/stat.h> header.
Therefore we have to handle the use of this header in strictly
standard-compliant sources special. */
struct timespec st_atim; /* Time of last
access. */
struct timespec st_mtim; /* Time of last modification. */
struct timespec st_ctim; /* Time of last status change. */
# define st_atime st_atim.tv_sec /* Backward compatibility. */
# define st_mtime st_mtim.tv_sec
# define st_ctime st_ctim.tv_sec
#else
__time_t st_atime; /* Time of last
access. */
__syscall_ulong_t st_atimensec; /* Nscecs of last
access. */
__time_t st_mtime; /* Time of last modification. */
__syscall_ulong_t st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /* Time of last status change. */
__syscall_ulong_t st_ctimensec; /* Nsecs of last status change. */
#endif
#ifdef __x86_64__
__syscall_slong_t __glibc_reserved[3];
#else
# ifndef __USE_FILE_OFFSET64
unsigned long int __glibc_reserved4;
unsigned long int __glibc_reserved5;
# else
__ino64_t st_ino; /* File serial number. */
# endif
#endif
};
4.3文件類型
看過了上面的stat結構體,隨便感受了1下stat結構體的內容,接下來對其中幾個重要的字段進行研究,首先來看:
__mode_t st_mode;
先來看看“ __mode_t”的類型,相干定義位于:/usr/include/x86_64-linux-gnu/bits/type.h中,具體定義以下:
# define __STD_TYPE typedef
__STD_TYPE __MODE_T_TYPE __mode_t;
#define __MODE_T_TYPE __U32_TYPE ///usr/include/x86_64-linux-gnu/bits/typesize.h
#define __U32_TYPE unsigned int
這1大堆,來回來去的。
根據APUE,文件共包括以下幾類:
- 普通文件
- 目錄文件
- 塊特殊文件
- 字符特殊文件
- FIFO
- 套接字
- 符號鏈接
好了,再來看看linux的有關內容,還是位于/usr/include/x86_64-linux-gnu/sys/stat.h中
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
#define S_ISCHR(mode) __S_ISTYPE((mode), __S_IFCHR)
#define S_ISBLK(mode) __S_ISTYPE((mode), __S_IFBLK)
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
#ifdef __S_IFIFO
# define S_ISFIFO(mode) __S_ISTYPE((mode), __S_IFIFO)
#endif
#ifdef __S_IFLNK
# define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
#endif
# define S_ISSOCK(mode) __S_ISTYPE((mode), __S_IFSOCK)
#ifdef __USE_POSIX199309
# define S_TYPEISMQ(buf) __S_TYPEISMQ(buf)
# define S_TYPEISSEM(buf) __S_TYPEISSEM(buf)
# define S_TYPEISSHM(buf) __S_TYPEISSHM(buf)
#endif
好了,通過上面的定義可以了解到這些宏定義說到底就是通過1個參數與__S_IFMT進行“與運算”,得到值后與函數的本來功能進行比較,最后返回0或1。
在上1章中我們留下了1個疑問,通過lseek函數可以設定文件的偏移量,但如果文件描寫符指向管道、FIFO(命名管道)、網絡套接字,則lseek返回⑴,并將errno設置為ESPIPE。所以我們得到結論文件描寫符0、1、2是管道或命名管道。現在終究可以通過實驗驗證1下了:
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
struct stat buf;
fstat(STDIN_FILENO,&buf);
if(S_ISFIFO(buf.st_mode));
printf("stdin is fifo\n");
fstat(STDOUT_FILENO,&buf);
if(S_ISFIFO(buf.st_mode));
printf("stdout is fifo\n");
fstat(STDERR_FILENO,&buf);
if(S_ISFIFO(buf.st_mode));
printf("stderr is fifo\n");
return 0;
}
運行結果以下:
./test_stat
stdin is fifo
stdout is fifo
stderr is fifo
通過以上實驗也驗證了我們的推測——文件描寫符0、1、2是管道或命名管道。
4.4 節主要討論設置用戶ID與用戶組ID的問題,書中給出了1些分析,不過我感覺說的不是很清楚,所以給大家分享1篇blog:http://blog.chinaunix.net/uid⑴8905703-id⑶843177.html
關于以上概念,結合我看到的1些資料,給大家做1個簡單的總結。關于這幾個概念的辨別,還是從現象動身,1個程序要履行首先要知道程序的“有功效戶ID”、“有效組ID”、“附屬組ID”,知道了以上3個“ID”后還不夠,我們還要檢查當前的用戶“ID”是不是與以上3個“ID”相匹配,而這個當前的用戶“ID”就是“實際用戶ID”與“實際組ID”,也就是登錄系統時所用到的身份驗證信息。1般來講,當履行1個程敘文件時,進程的有功效戶ID通常就是實際用戶ID,有效組ID通常是實際組ID。但也有特殊情況就是書中提到的passwd命令的履行,關于這個命令的詳細分析大家可以參考上面那篇blog。
4.5 文件訪問權限
這1節主要要給大家分享1下在訪問文件進程中所用到的隱藏權限,這里隱藏的權限是指除訪問文件所需要的權限外,還需要的額外的權限,具體內容以下:
- 通過文件名打開任意類型的文件時,對文件名(絕對路徑)中包括的每個目錄,包括它可能隱含確當前工作目錄都應具有履行權限。這里還要強調1下目錄的讀權限與履行權限的不同意義,讀權限允許我們讀目錄,取得在該目錄中所有文件名的列表。當1個目錄是我們要訪問文件的路徑名的1個組成部份時,對該目錄的履行權限使我們可通過該目錄(也就是搜索該目錄,尋覓1個特定的文件名)。
- 對1個文件的讀權限決定了我們是不是能夠打開現有文件進行讀操作。這與open函數的O_RDONLY和O_RDWR相干。
- 對1個文件的寫權限決定了我們是不是能夠打開現有文件進行寫操作。這與open函數的O_WRONLY和O_RDWR相干。
- 為了在open函數中對1個文件指定O_TRUNC標志,必須對該文件具有寫權限。
- 為了在1個目錄中創建1個新文件,必須對該目錄具有寫權限和履行權限。之所以需要履行權限是由于在創建文件前需要查找當前目錄中是不是已有該文件。
- 為了刪除1個現有文件,必須對包括該文件的目錄具有寫權限和履行權限(刪除之前還是要進行查找操作)。對該文件本身則不需要有讀、寫權限。
- 如果用7個exec函數中的任何1個履行某個文件,都必須對該文件具有履行權限。該文件還必須是1個不同文件。
進程每次打開、創建或刪除1個文件時,內核就進行文件訪問權限測試,這類測試觸及兩方面:1方面是文件的所有者,另外一方面是履行操作的進程。對文件的所有者進行管理主要觸及:st_uid(用戶ID)、st_gid(用戶組ID),對進程的權限管理需要3個字段:有功效戶ID、有限組ID、附屬組ID。
有了標識進程與文件權限的信息位,再來就是對這些信息位進行比較,若符合則代表具有權限,若不符則不代表具有相應的權限。以下是內核進行的具體測試進程:
- 若進程的有功效戶ID是0(超級用戶),則允許訪問。這給予了超級用戶對全部文件系統進行處理的最充分的自由。
- 若進程的有功效戶ID等于文件的所有者ID(也就是進程具有此文件),那末如果所有者適當的訪問權限位被設置,則允許訪問;否則謝絕訪問。
- 若進程的有效組ID或進程的附屬組ID之1等于文件的組ID,那末如果組適當的訪問權限位被設置,則允許訪問;否則謝絕訪問。
- 若其他用戶適當的訪問權限位被設置,則允許訪問;否則謝絕訪問。
以上4個步驟順序履行,其中若履行到1個權限規則相匹配則跳出測試,不再進行接下來的測試步驟。
4.6 新文件和目錄的所有權
使用open或create創建新文件時,新文件的用戶ID設置為進程的有功效戶ID。關于組ID可以有以下兩個選項:
- 新文件的組ID可以是進程的有效組ID。
- 新文件的組ID可以是它所在目錄的組ID。這類選項的作用是使在某個目錄下創建的文件和目錄都具有該目錄的組ID,因而文件和目錄的組所有權從該點向下傳遞。
對linux操作系統如果設置組ID位被設置則新文件的組ID設置為目錄的組ID;否則新文件的組ID設置為進程的有效組ID。
好了,說了這么多有關于權限的問題,讓我們回過頭來再看看在上1章中留下的問題,當時留下的問題是“先在沒有寫權限的情況下創建文件,即此時文件僅具有讀權限,然后寫入數據,根據我的實驗若文件不存在則可以成功寫入數據。此時文件已存在,再通過讀寫權限打開文件則出現無權限毛病”。對后1點毛病我們已可以理解了,確切是沒有無權限,因爾后來我們加入了“寫權限”,則可以成功寫入數據,但對第1點還不是很明白:“沒甚么沒有寫權限卻可以寫入數據?”。
4.7 access和faccessat函數
先來看看這兩個函數的原型:
#include <unistd.h>
extern int
access (const char *__name, int __type) __THROW __nonnull ((1));
extern int f
accessat (int __fd, const char *__file, int __type, int __flag)
__THROW __nonnull ((2)) __wur;
這兩個函數的功能是依照實際用戶ID和實際組ID來測試文件的訪問能力,注意此處1定要兩個權限都測試成功,才會返回成功,否則則返回失敗。再來看看我們能測試哪些權限,在<unistd.h>中有以下定義,上述定義用于函數的type參數。
#define R_OK 4 /* Test for read permission. */ //通過注釋就能夠了解其功能,測試讀權限
#define W_OK 2 /* Test for write permission. */ //測試寫權限
#define X_OK 1 /* Test for execute permission. */ //測試履行權限
#define F_OK 0 /* Test for existence. */ //測試是不是存在
access函數通過其定義可以發現,使用文件名標識被測試的文件。faccessat函數通過fd(指向某個文件夾)與文件名共同肯定被測試文件。其中若faccessat函數的__flag參數設定為AT_EACCESS,則訪問檢查用的是調用進程的有功效戶ID和有效組ID(一樣依照前面的測試順序,遇到匹配項就跳出),而不是實際用戶ID和實際組ID。
通過書中的示例,對access函數的功能進行簡單的測試,源碼以下:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc,char* argv[])
{
if(
access(argv[1],R_OK)<0 ) perror(argv[0]);
else printf("read
access OK\n");
if( open(argv[1],O_RDONLY)<0 ) perror(argv[0]);
else printf("open for reading OK\n");
return 0;
}
運行結果以下:
再來看看/etc/shadow文件的運行情況:
./test_
access /etc/shadow
./test_
access: Permission denied
./test_
access: Permission denied
沒有權限運行,所以做1些調劑再試試:
su //切換到root用戶
chown root test_
access //切換用戶ID為root,通過這1步操作就能夠使用open函數打開文件
chmod u+s test_
access //打開用戶設置用戶ID位,設置用戶ID位的作用用1句話概括就是“履行者將具有該程序所有者的權限”,在我們的例子中就是普通用戶具有root用戶的讀
權限
ls -l test_
access //此時程序的所有者已變成root用戶,同時設置用戶ID位也被設置——“s”。
-rwsrwxr-x 1 root 8712 6月 26 17:36 test_
access
exit //返回普通用戶
./test_
access /etc/shadow
./test_
access: Permission denied //本來設置了“s”位,普通用戶應當具有與root用戶相同的權限,即普通用戶一樣可以讀權限,但由于
access函數使用實際用戶ID與實際組ID進行
測試,所以出現無權限毛病。
open for reading OK //同理由于設置了“s”位,而root用戶具有讀權限,普通用戶具有與root用戶相同的權限,則可以通過open函數打開。
(關于ubuntu如何切換到超級用戶請見以下blog:http://blog.csdn.net/david_xtd/article/details/7229325)。
4.8 umask函數
umask函數為進程設置文件模式創建屏蔽字,并返回之前的值(這是少數幾個沒有出錯返回函數中的1個)。函數原型:
#include <sys/stat.h>
extern __mode_t umask (__mode_t __mask) __THROW;
其中,參數cmask是由9個常量中的若干個按位“或”構成的。在文件模式創建屏蔽字中為1的位,在文件mode中的相應位1定被關閉。
通過1個實例感受以下函數的功能,源碼以下:
#include <fcntl.h>
#include <unistd.h>
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
int main(int argc,char* argv[])
{
umask(0);
if(creat("foo",RWRWRW)<0) perror(argv[0]);
umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if(creat("bar",RWRWRW)<0) perror(argv[0]);
return 0;
}
運行結果以下:
ls -l foo bar
-rw------- 1 andywang andywang 0 6月 26 21:16 bar
-rw-rw-rw- 1 andywang andywang 0 6月 26 21:16 foo
通過實驗可以發現,umask(0)沒有屏蔽任何字,所以foo文件可以依照我們設定的權限進行創建,但由于在創建bar文件之前通過umask函數屏蔽了S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH,則在創建bar時文件的讀寫權限僅保存S_IRUSR|S_IWUSR。通過這個實驗可以得出結論umask的效果可以1直延續直到進程結束。更改進程的文件模式創建屏蔽字其實不影響其父進程(常常是shell)的屏蔽字。但不知道exec函數是不是能夠延續umask函數的效果,此處留下1個疑問?
4.9 chmod、fchmod、fchmodat函數
先來看看函數原型:
#include <sys/stat.h>
extern int chmod (const char *__file, __mode_t __mode)
__THROW __nonnull ((1));
extern int fchmod (int __fd, __mode_t __mode) __THROW;
extern int fchmodat (int __fd, const char *__file, __mode_t __mode,
int __flag)
__THROW __nonnull ((2)) __wur;
以上3個函數的功能是更改現有文件的訪問權限。chmod函數在指定的文件上進行操作,而fchmod函數則對已打開的文件進行操作。fchmodat函數則對已打開的文件進行操作。fchmodat函數與chmod函數在下面兩種情況下是相同的:1種是pathname參數為絕對路徑,另外一種是fd參數取值為AT_FDCWD而pathname參數為相對路徑。否則,fchmodat計算相對打開目錄(由fd參數指向)的pathname。flag參數可以用于改變fchmodat的行動,當設置了AT_SYMLINK_NOFOLLOW標志時,fchmodat其實不會跟隨符號鏈接。
為了改變1個文件的權限位,進程的有功效戶ID必須等于文件所有者ID,或該進程必須具有超級用戶權限。
除前文中提到的9個權限位外還有6個權限位,全部權限以下:
#define S_ISUID __S_ISUID /* Set user ID on execution. */
#define S_ISGID __S_ISGID /* Set group ID on execution. */
# define S_ISVTX __S_ISVTX
#define S_IRUSR __S_IREAD /* Read by owner. */
#define S_IWUSR __S_IWRITE /* Write by owner. */
#define S_IXUSR __S_IEXEC /* Execute by owner. */
#define S_IRWXU (__S_IREAD|__S_IWRITE|__S_IEXEC)
#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */
#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */
#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */
/* Read, write, and execute by group. */
#define S_IRWXG (S_IRWXU >> 3)
#define S_IROTH (S_IRGRP >> 3) /* Read by others. */
#define S_IWOTH (S_IWGRP >> 3) /* Write by others. */
#define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */
/* Read, write, and execute by others. */
#define S_IRWXO (S_IRWXG >> 3)
好了,還是結合書中的例子看1下,源碼以下:
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
int main(int argc,char* argv[])
{
struct stat statbuf;
if( stat("foo",&statbuf)<0 ) perror(argv[0]);
if( chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) <0 ) perror(argv[0]);
if( chmod("bar", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ) <0 ) perror(argv[0]);
return 0;
}
運行結果以下,還是結合umask函數創建的文件繼續進行實驗。
ls -l bar foo
-rw------- 1 andywang andywang 0 6月 27 22:31 bar
-rw-r--r-- 1 andywang andywang 0 6月 27 22:31 foo
運行chmod后結果以下:
ls -l bar foo
-rw-r--r-- 1 andywang andywang 0 6月 27 22:32 bar
-rw-rwSrw- 1 andywang andywang 0 6月 27 22:32 foo
先來看看bar文件。比較簡單,就是摒棄原來的文件權限,依照新的文件權限進行設置。
再來是foo文件,首先通過stat函數取得已有的文件權限,再來通過操作關閉“組履行”權限,并打開“履行時設置組ID”標志(在ls命令中以“S”體現)。此處要注意的1點是:“S”代表不包括履行位,“s”代表包括履行位。chmod不會影響文件的最后修改時間。
好了,說了這么多讓我們來看看文件權限計算究竟是怎樣進行的,我們已知道了文件權限標志是如何定義的,讓我們來看看具體值:
#define __S_ISUID 04000 /* Set user ID on execution. */
#define __S_ISGID 02000 /* Set group ID on execution. */
#define __S_ISVTX 01000 /* Save swapped text after use (sticky). */
#define __S_IREAD 0400 /* Read by owner. */
#define __S_IWRITE 0200 /* Write by owner. */
#define __S_IEXEC 0100 /* Execute by owner. */
(以上定義位于/usr/include/x86_64-linux-gnu/bits/stat.h中)
好了,文件權限的實際值就是:
#define S_ISUID __S_ISUID //04000,數字以“0”開頭,說明是8進制數字
#define S_ISGID __S_ISGID //02000
# define S_ISVTX __S_ISVTX //01000
#define S_IRUSR __S_IREAD //0400
#define S_IWUSR __S_IWRITE //0200
#define S_IXUSR __S_IEXEC //0100
#define S_IRWXU (__S_IREAD|__S_IWRITE|__S_IEXEC) // 0700
#define S_IRGRP (S_IRUSR >> 3) //左移3位,變成0040
#define S_IWGRP (S_IWUSR >> 3) //左移3位,變成0020
#define S_IXGRP (S_IXUSR >> 3) //左移3位,變成0010
/* Read, write, and execute by group. */
#define S_IRWXG (S_IRWXU >> 3) //左移3位,變成0070
#define S_IROTH (S_IRGRP >> 3) //在0040的基礎上再次左移3位,變成0004
#define S_IWOTH (S_IWGRP >> 3) //0002
#define S_IXOTH (S_IXGRP >> 3) //0001
/* Read, write, and execute by others. */
#define S_IRWXO (S_IRWXG >> 3) //0007
通過上面的計算,可以發現權限位的值與“chmod”命令中所使用的值完全相同,不同權限之間使用“|”運算進行計算,這1點沒有甚么問題。
再來看看關閉1個標志位所進行的計算,通過上面的例子可以看到,關閉1個權限位所使用的是“先取反,再進行與運算”。還是結合上面的代碼來看1看,“S_IXGRP”的值為“0010”編程2進制就是“000001000”(首位的0不參與運算),此時期表唯一“組履行”權限開啟,取反后變成“111110111”,唯一“組履行”位關閉,此時進行與運算,則“組履行”位1定會被關閉,而其他權限位則保持不變,如此就實現了關閉“組履行”位的功能。
4.10 粘著位
有關于粘著位的功能請見以下blog:http://os.51cto.com/art/201004/194994.htm
當前,粘著位對普通文件已沒有作用了,但如果目錄的粘著位被設置,則可以起到保護其中文件的作用。
4.11 chown、fchown、fchownat、lchown函數
已看過了更改權限的函數,以上幾個函數的主要功能就是改變文件的主人,對應的命令就是chown。與改變權限的那幾個函數特點類似,在此就不詳細分析了。
4.12 文件長度
stat結構成員st_size表示以字節為單位的文件的長度。此字段只對普通文件、目錄文件和符號鏈接成心義。對目錄,文件長度通常是1個數(如16或512)的整倍數。對符號鏈接,文件長度是在文件名中的實際字節數。
同時本小節再次討論了與文件空洞有關的內容:
在第3章中我們通過實驗創建了兩個文件,其中1個帶有文件空洞,可通過du命令查看文件實際占用的磁盤塊個數,命令以下:
du -s file.hole
8 file.hole
由于在我的機器上,POSIXLY_CORRECT沒有被設置,所以du命令報告的是512字節塊的塊數,所以file.hole實際占用的磁盤容量是4096字節,通過wc命令可以查看正常的I/O操作讀全部文件長度:
wc -c file.hole
16394 file.hole
該長度與通過ls得到的長度相同。
如果使用實用程序復制這個文件,那末所有這些空洞都會被填滿,其中所有實際數據字節皆被填寫為0,操作以下:
cat file.hole > file.hole.copy
du file.hole.copy
20 file.hole.copy //此時有空洞的文件所占用的磁盤塊數也是20
好了,說了這么多,通過實驗來研究1下,到底st_size的值與那個命令最后得到的值相同,源么以下:
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
int main(int argc,char* argv[])
{
struct stat statbuf;
if( stat("file.hole",&statbuf)<0 ) perror(argv[0]);
else printf("%ld\n",statbuf.st_size);
if( stat("file.nohole",&statbuf)<0 ) perror(argv[0]);
else printf("%ld\n",statbuf.st_size);
if( stat("file.hole.copy",&statbuf)<0 ) perror(argv[0]);
else printf("%ld\n",statbuf.st_size);
return 0;
}
運行結果以下:
./test_st_size
16394
16394
16394
與ls命令的結果相同。
4.13 文件截斷
將文件截取為1定length可通過以下函數:
#include <unistd.h>
extern int truncate (const char *__file, __off_t __length)
__THROW __nonnull ((1)) __wur;
extern int ftruncate (int __fd, __off_t __length) __THROW __wur;
以上兩個函數定義在unstd.h中,說明上述函數是系統調用,與上面的幾個函數具有1定的區分。這里要注意的1點是如果該文件之前的長度大于length,則超過length之外的數據就不再能訪問了。如果之前的長度小于length,文件長度將增加,在之前的文件尾端和新的文件尾端之間的數據將讀作0。我認為這個函數的功能與lseek類似,都是直接設置當前文件偏移量。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈