4、标准IO编程和文件IO编程
1、标准IO编程
本节所要讨论的I/O操作都是基于流的,它符合ANSI C的标准。有一些函数读者已经非常熟悉了(如printf()和scanf()函数等),因此本节仅介绍常用的函数。
1.1、流的打开
使用标准IO打开文件的函数有fopen()、fdopen()和freopen()。它们可以以不同的模式打开文件,都返回一个指向FILE的指针,该指针指向对应的IO流。此后,对文件的读写都通过这个FILE指针来进行。其中,fopen()可以指定打开文件的路径和打开模式,fdopen()可以指定打开的文件描述符和模式,而freopen()除了可以指定打开的文件和打开模式外,还可以指定特定的IO流。
fopen()函数没有设定创建文件权限的参数,POSIX.1要求具有如下权限,由于umask的默认值为0002,所以新建普通文件的默认权限为0664或者-rw-rw-r--,目录的默认权限为drwxrwxr-x)。
umask值则表明了需要从默认权限中去掉哪些权限来成为最终的默认权限值。用户可以通过umask修改文件存取的权限,0777 & ~umask或umask(0777)。 (文件的权限 = 设置权限 & ~umask)。也可以修改umask的值,这样在新建文件或文件夹的时候就可以直接设置其权限,直接输入umask xxxx就可以修改umask的值,输入umask就可以查看umask的值。
/*FILE结构体*/ #ifndef _FILE_DEFINED struct _iobuf { char *_ptr; //文件输入的下一个位置 int _cnt; //当前缓冲区的相对位置 char *_base; //指基础位置(即是文件的其始位置) int _flag; //文件标志 int _file; //文件的有效性验证 int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取 int _bufsiz; //缓冲区大小 char *_tmpfname; //临时文件名 }; typedef struct _iobuf FILE;
| 头文件 | #include <stdio.h> | |
| 函数原型 | FILE *fopen(const char *path,const char * mode); | |
| 作用 | 打开文件流。fopen() 会获取文件信息,包括文件名、文件状态、当前读写位置等,并将这些信息保存到一个 FILE 类型的结构体变量中,然后将该变量的地址返回。 | |
| 参数 | path | 要打开的文件(包含文件路径和文件名) | 
| mode | 文件的打开方式 | |
| 返回值 | 成功 | 指向FILE的指针 | 
| 失败 | NULL | |
| 头文件 | #include <stdio.h> | |
| 函数原型 | FILE * fdopen(int fildes,const char * mode); | |
| 作用 | fdopen函数用一个现存的文件描述符(我们可能从 open,dup,dup2,fcntl,pipe,socket,socketpair,accept等函数得到此文件描述符)和一个标准的I / O流相结合。 此函数常用于由创建管道和创建网络通信通道函数时获得的描述符。因为这些特殊类型的文件不能用标准I/O fopen函数打开,首先必须先调用设备专用函数以获得一个文件描述符,然后用fdopen使一个标准I/O流与该描述符相结合。 通过文件描述符获取文件流 | |
| 参数 | fildes | 文件描述词,fdopen()会将参数fildes 的文件描述词,转换为对应的文件指针后返回。 | 
| mode | 文件的打开方式 | |
| 返回值 | 成功 | 指向FILE的指针 | 
| 失败 | NULL | |
| 头文件 | #include <stdio.h> | |
| 函数原型 | FILE *freopen( const char *path, const char *mode, FILE *stream ); | |
| 作用 | 实现重定向,把预定义的标准流文件定向到由path指定的文件中。标准流文件具体是指stdin、stdout和stderr。其中stdin是标准输入流,默认为键盘;stdout是标准输出流,默认为屏幕;stderr是标准错误流,一般把屏幕设为默认。 | |
| 参数 | path | 用于存储输入输出的自定义文件名 | 
| mode | 文件的打开方式 | |
| stream | 一个文件,通常使用标准流文件 | |
| 返回值 | 成功 | 则返回一个path所指定文件的指针 | 
| 失败 | NULL | |
| 控制读写权限的字符串(必须指明) | |
| 打开方式 | 说明 | 
| r | 以“只读”方式打开文件。只允许读取,不允许写入。文件必须存在,否则打开失败。 | 
| w | 以“写入”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 | 
| a | 以“追加”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。 | 
| R+ | 以“读写”方式打开文件。既可以读取也可以写入,也就是随意更新文件。文件必须存在,否则打开失败。 | 
| W+ | 以“写入/更新”方式打开文件,相当于w和r+叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 | 
| a+ | 以“追加/更新”方式打开文件,相当于a和r+叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。 | 
| 控制读写方式的字符串(可以不写) | |
| 打开方式 | 说明 | 
| t | 文本文件。如果不写,默认为"t"。 | 
| b | 二进制文件。在每个选项中加入b用来告诉函数库打开的文件为二进制文件,而非纯文本文件。在Linux系统中会忽略该符号。 | 
当用户程序运行时,系统自动打开了3个流:标准输入流stdin、标准输出流stdout、标准错误流stderr。stdin用来从标准输入设备(默认时键盘)中读取输入内容,stdout用来向标准输出设备(默认是当前终端)输出内容;stderr用来向标准错误设备(默认是当前终端)输出错误信息。
1.2、流的读/写
(1)按字符输入/输出(一次读/写一个字节)
| 头文件 | #include <stdio.h> | |
| 函数原型 | int getc(FILE * stream); int fgetc(FILE * stream); int getchar(void); | |
| 作用 | getc和fgetc从指定的文件流中读取一个字符,getchar从stdin中读取一个字节标志。 | |
| 参数 | stream | 指定的文件流 | 
| 返回值 | 成功 | 返回读取到的字符 | 
| 失败或到文件结束标志 | EOF | |
| 头文件 | #include <stdio.h> | |
| 函数原型 | int putc(int c,FILE * stream); int fputc(int c,FILE * stream); int fputchar(int c); | |
| 作用 | putc和fputc向指定的流写入一个字符,fputchar函数向stdout写入一个字符 | |
| 参数 | c | 要写入的字符 | 
| 
 | stream | 指定的文件流 | 
| 返回值 | 成功 | 写入的字符c | 
| 失败 | EOF | |
(2)按行输入/输出(一次读/写一行)
| 头文件 | #include <stdio.h> | ||
| 函数原型 | char *gets(char *s); char *fgets(char *s,int size,FILE * stream); | ||
| 作用 | gets函数容易造成缓冲区溢出,不推荐使用 fgets从指定的流中读取一个字符串,当遇到\n时,会读取\n或读取size-1个字符后返回。注意:fgets不能保证每次都能读出一行。 | ||
| 参数 | s | 存放读取数据的首地址 | |
| size | 要读取的字符串长度 | ||
| stream | 指定的文件流 | ||
| 返回值 | 成功 | s | |
| 失败或达到文件末尾 | NULL | ||
| 头文件 | #include <stdio.h> | ||
| 函数原型 | char puts(const char *s); char fputs(const char *s,FILE * stream); | ||
| 作用 | 往指定的文件流中写入数据 | ||
| 参数 | s | 存放要写入的数据的首地址 | |
| stream | 对应的文件流 | ||
| 返回值 | 成功 | s | |
| 失败或达到文件末尾 | NULL | ||
(3)以指定大小为单位读/写文件
| 头文件 | #include <stdio.h> | |
| 函数原型 | size_t fread(void *ptr,size_t size,size_t nmemb, FILE * stream); | |
| 作用 | 从指定的文件流中读取数据 | |
| 参数 | ptr | 存放读取到的数据的缓冲区 | 
| size | 每次读取的数据长度 | |
| nmemb | 读取的次数 | |
| stream | 要读取的文件流 | |
| 返回值 | 成功 | 返回实际读取的次数 | 
| 失败 | EOF | |
| 头文件 | #include <stdio.h> | |
| 函数原型 | size_t fwrite(const void *ptr,size_t size,size_t nmemb, FILE * stream); | |
| 作用 | 往指定的文件流中写入数据 | |
| 参数 | ptr | 指向要写入的数据 | 
| size | 每次写入的数据长度 | |
| nmemb | 写入的次数 | |
| stream | 要写入的文件流 | |
| 返回值 | 成功 | 返回实际写入次数 | 
| 失败 | EOF | |
1.3、流的定位
每个打开的流内部都有一个当前读写位置。流在打开时,当前读写位置为0,表示文件的开始位置。每读写一次后,当前读写位置自动增加实际读写的大小。在读写流之间可先对流进行定位,即移动到指定的位置再操作。
| 头文件 | #include <stdio.h> | ||
| 函数原型 | int fseek(FILE * stream,long offset,int whence); | ||
| 作用 | 读写文件时流的定位 | ||
| 参数 | stream | 要定位的文件流 | |
| offset | 相对于基准值的偏移量 | ||
| Whence:基准值 | SEEK_SET | 代表文件起始位置 | |
| SEEK_END | 代表文件结束位置 | ||
| SEEK_CUR | 代表文件当前读写位置 | ||
| 返回值 | 成功 | 0 | |
| 失败 | EOF | ||
| 头文件 | #include <stdio.h> | |
| 函数原型 | long ftell(FILE * stream); | |
| 作用 | 读写文件时流的定位 | |
| 参数 | stream | 要定位的文件流 | 
| 返回值 | 成功 | 返回当前读写位置 | 
| 失败 | EOF | |
1.4、格式化输入/输出
在前面编写的测试代码中,会经常使用到库函数 printf()用于输出程序中的打印信息, printf()函数可将格式化数据写入到标准输出,所以通常称为格式化输出。除了 printf()之外,格式化输出还包括: fprintf()、dprintf()、 sprintf()、 snprintf()这 4 个库函数。
除了格式化输出之外,自然也有格式化输入,从标准输入中获取格式化数据,格式化输入包括: scanf()、fscanf()、 sscanf()这三个库函数,那么本小节将向大家介绍 C 语言库函数的格式化 I/O。
(1)格式化输出
C 库函数提供了 5 个格式化输出函数,包括: printf()、 fprintf()、 dprintf()、 sprintf()、 snprintf(),其函数定义如下所示:
#include <stdio.h> int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int dprintf(int fd, const char *format, ...); int sprintf(char *buf, const char *format, ...); int snprintf(char *buf, size_t size, const char *format, ...);
(2)格式化输入
C 库函数提供了 3 个格式化输入函数,包括: scanf()、 fscanf()、 sscanf(),其函数定义如下所示:
#include <stdio.h> int scanf(const char *format, ...); int fscanf(FILE *stream, const char *format, ...); int sscanf(const char *str, const char *format, ...);
格式化输入/输出函数可以指定输入/输出的具体格式,包括非常熟悉的printf()、scanf()等函数。
| 头文件 | #include <stdio.h> | |
| 函数原型 | int scanf(const char *format,…); int fscanf(FILE *fp,const char *format,…); int sscanf(char *buf,const char *format,…); | |
| 作用 | 
 | |
| 参数 | format | 输入的格式 | 
| fp | 作为输入的流 | |
| buf | 作为输入的缓冲区 | |
| 返回值 | 成功 | 输出字符数(sprintf返回存入数组中的字符数) | 
| 失败 | EOF | |
| 头文件 | #include <stdio.h> | |
| 函数原型 | int printf(const char *format,…); int fprintf(FILE *fp,const char *format,…); int sprintf(char *buf,const char *format,…); | |
| 作用 | 
 | |
| 参数 | format | 输出的格式 | 
| fp | 接收输出的流 | |
| buf | 接收输出的缓冲区 | |
| 返回值 | 成功 | 输出字符数(sprintf返回存入数组中的字符数) | 
| 失败 | EOF | |
1.5、错误处理
| 头文件 | #include <stdio.h> | |
| 函数原型 | void perror(const char *s); | |
| 作用 | 标准IO函数执行时如果出现错误,会把错误码保存在全局变量errno中。可以通过相应的函数打印错误信息。 | |
| 参数 | s | 在标准错误流上输出的信息 | 
| 返回值 | 无 | |
| 头文件 | #include <string.h> #include <errno.h> | |
| 函数原型 | char *strerror(int errnum); | |
| 作用 | 
 | |
| 参数 | errnum | 错误码 | 
| 返回值 | 错误码对应的错误信息 | |
| 头文件 | #include <stdio.h> | |
| 函数原型 | void exit(int status); | |
| 作用 | 退出当前程序。当一个进程正常终止时(直接调用exit函数或从main函数返回),则所有带未写缓存数据的标准I/O流都被刷新,所有打开的标准I/O流都被关闭。 | |
| 参数 | status | 0:程序正常退出 | 
| 非0:程序异常退出 | ||
| 返回值 | 无 | |
1.6、文件流的关闭
| 头文件 | #include <stdio.h> | |
| 函数原型 | int fclose(FILE *stream); | |
| 作用 | 关闭指定的文件流,在该函数关闭文件之前,刷新缓存中的数据。如果标准I/O库已经为该流自动分配了一个缓存,则释放此缓存。 | |
| 参数 | stream | 指定的文件流 | 
| 返回值 | 成功 | 0 | 
| 失败 | EOF | |
1.7 、检查或复位状态
调用 fread()读取数据时,如果返回值小于参数 nmemb 所指定的值,表示发生了错误或者已经到了文件末尾(文件结束 end-of-file),但 fread()无法具体确定是哪一种情况; 在这种情况下,可以通过判断错误标志或 end-of-file 标志来确定具体的情况。
(1)feof()函数
库函数 feof()用于测试参数 stream 所指文件的 end-of-file 标志,如果 end-of-file 标志被设置了,则调用feof()函数将返回一个非零值,如果 end-of-file 标志没有被设置,则返回 0。
其函数原型如下所示:
#include <stdio.h>
int feof(FILE *stream);
当文件的读写位置移动到了文件末尾时, end-of-file 标志将会被设置。
if (feof(file)) { /* 到达文件末尾 */ } else { /* 未到达文件末尾 */ }
(2)ferror()函数
库函数 ferror()用于测试参数 stream 所指文件的错误标志,如果错误标志被设置了,则调用 ferror()函数将返回一个非零值,如果错误标志没有被设置,则返回 0。
其函数原型如下所示:
#include <stdio.h>
int ferror(FILE *stream);
当对文件的 I/O 操作发生错误时,错误标志将会被设置。
if (ferror(file)) { /* 发生错误 */ } else { /* 未发生错误 */ }
(3)clearerr()函数
  库函数 clearerr()用于清除 end-of-file 标志和错误标志,当调用 feof()或 ferror()校验这些标志后,通常需要清除这些标志,避免下次校验时使用到的是上一次设置的值,此时可以手动调用 clearerr()函数清除标志。
  clearerr()函数原型如下所示:
#include <stdio.h>
void clearerr(FILE *stream);
此函数没有返回值,调用将总是会成功!
对于 end-of-file 标志,除了使用 clearerr()显式清除之外,当调用 fseek()成功时也会清除文件的 end-offile 标志。
2、文件IO编程
本节所讨论的是基于文件描述符的。所谓文件描述符就是按顺序分配的非负整数,内核用此来标识一个特定进程正在访问的文件,它也是socket、pipe等的访问标识。
标准输入、标准输出、标准出错的文件描述符分别是0、1、2.
通过文件描述符访问时不需要缓存的I/O
2.1、文件的打开
| 头文件 | #include <sys/stat.h> #include <fcntl.h> | |
| 函数原型 | int open(const char *pathname,int flags,int perms); | |
| 作用 | open()函数用于创建或打开文件,在打开或创建文件时可以指定文件打开方式及文件的访问权限。 该函数中的flags参数可以通过“|”组合构成,但前3个标志常量(O_RDONLY、O_WRONLY、O_RDWR)不能相互组合 | |
| 参数 | pathname | 要打开的文件(包括路径) | 
| flags:文件的打开方式 | O_RDONLY:以只读方式打开文件 | |
| O_WRONLY:以只写方式打开文件 | ||
| O_RDWR:以读写方式打开文件 | ||
| O_CREAT:如果该文件不存在,就创建一个新的文件,并用第3个参数为其设置权限 | ||
| O_EXCL:如果使用O_CREAT时文件存在,则可返回错误信息。这一参数可测试文件是否存在 | ||
| O_NOCTTY:使用本参数时,若打开的时终端文件,那么该终端不会成为当前进程的控制终端 | ||
| O_TRUNC:若文件已经存在,那么会删除文件中的全部原有数据,并且设置文件大小为0 | ||
| O_APPEND:以添加方式打开文件,在写文件时,文件读写位置自动指向文件的末尾,即将写入的数据添加到文件的末尾 | ||
| perms | 新建文件的存取权限 可以用一组宏定义:S_I(R/W/X)(USR/GRP/OTH) 其中R/W/X分别表示读/写/执行权限 USR/GRP/OTH分别表示文件所有者/文件所属组/其它用户 例如,S_IRUSR | S_IWUSR表示设置文件所有者的可读可写属性。八进制表示法中0600也表示同样的权限。 | |
| 返回值 | 成功 | 返回文件描述符 | 
| 失败 | -1 | |
| 头文件 | #include <stdio.h> | |
| 函数原型 | int fileno(FILE *stream); | |
| 作用 | 已知文件流,获取对应的文件描述符 | |
| 参数 | stream | 文件流 | 
| 返回值 | 成功 | 文件描述符 | 
| 失败 | -1 | |
2.2、文件的读/写
| 头文件 | #include <unistd.h> | |
| 函数原型 | ssize_t read(int fd,void *buf,size_t count); | |
| 作用 | 该函数用来从指定的文件中读取数据到缓冲区,并返回实际读取的字节数 | |
| 参数 | fd | 文件描述符 | 
| buf | 用来存放读到的数据 | |
| count | 要读取的字节数 | |
| 返回值 | 成功 | 读到的字节数 | 
| 失败 | -1 | |
| 达到文件末尾 | 0 | |
| 头文件 | #include <unistd.h> | |
| 函数原型 | ssize_t write(int fd,void *buf,size_t count); | |
| 作用 | 将缓冲区数据写入指定的文件中,并返回实际写入的字节数。写操作从文件的当前读写位置开始写入。对磁盘文件进行读写操作时,若磁盘已满,该函数返回失败。 | |
| 参数 | fd | 文件描述符 | 
| buf | 指向要写入的数据的缓冲区 | |
| count | 要写入的字节数 | |
| 返回值 | 成功 | 已写的字节数 | 
| 失败 | -1 | |
2.3、文件定位
| 头文件 | #include <unistd.h> #include <sys/types.h> | ||
| 函数原型 | off_t lseek(int fd,off_t offset, int whence); | ||
| 作用 | 该函数用来决定从文件的何处开始读或写。它只能对可定位(可随机访问)文件操作。管道、套接字和大部分字符设备文件不支持此类操作。 | ||
| 参数 | fd | 文件描述符 | |
| offset | 相对于基准点whence的偏移量。以字节为单位,正数表示向前移动,负数表示向后移动 | ||
| whence | 当前位置的基点 | SEEK_SET:文件的起始位置 | |
| SEEK_CUR:文件当前读写位置 | |||
| SEEK_END:文件的结束位置 | |||
| 返回值 | 成功 | 文件当前读写位置 | |
| 失败 | -1 | ||
2.4、文件锁
前面介绍的函数实现了文件的打开、关闭、读写等,这里讨论的是在文件已经共享的情况下如何操作,也就是多个程序同时操作一个文件。Linux通常采用的方法是给文件上锁,来解决对共享资源的竞争。
文件锁包括建议性锁和强制性锁。建议性锁要求每个相关程序在访问文件之前检查是否有锁存在,并且尊重已有的锁。一般情况下,不建议使用建议性锁,因为无法保证每个程序都自动检查是否有锁。而强制性锁是由内核执行的锁,当一个文件被上锁,进行写入操作的时候,内核将阻止其它任何程序对该文件进行读写操作。采用强制性锁对性能的影响较大,每次读写操作内核都检查是否有锁存在。
在Linux中,实现文件上锁的函数有lockf()和fcntl(),其中lockf()用于对文件施加建议性锁,而fcntl()不仅可以施加建议性锁,还可以施加强制性锁。同时,fcntl()还能对文件的某一记录上锁,也就是记录锁。
记录锁又可以分为读取锁和写入锁,其中读取锁又称为共享锁,多个同时执行的程序允许在文件的同一部分建立读取锁。而写入锁又称为排斥锁,在任何时刻只能有一个程序在文件的某个部分上建立写入锁。显然,在文件的同一部分不能同时建立读取锁和写入锁。
fcntl()函数具有丰富的功能,它可以对已打开的文件进行各种操作。不仅能够管理文件锁,还可以获取和设置文件相关标志位以及复制文件描述符等。
| 头文件 | #include <sys/types.h> #include <unistd.h> #include <fcntl.h> | |
| 函数原型 | int fcntl(int fd,int cmd,….); | |
| 作用 | 
 | |
| 参数 | fd | 文件描述符 | 
| cmd | F_GETLK:检测文件锁状态 | |
| F_SETLK:设置lock描述的文件锁 | ||
| F_SETLKW:这是F_SETLK的阻塞版本(命令名中的w表示等待(wait)) | ||
| 在无法获取锁时,会进入睡眠状态;如果可以获取锁或者捕捉到信号则会返回 | ||
| 返回值 | 成功 | 0 | 
| 失败 | -1 | |
如果cmd和锁操作相关,则第三个参数的类型为struct *flock,其定义如下
Struct flock
{
         ……
         Short l_type;
         Off_t l_start;
         Short l_whence;
         Off_t l_len;
         Pid_t l_pid;
         ……
}
flock结构成员含义
| L_type | F_RDLCK:读取锁(共享锁) | 
| F_WRLCK:写入锁(排斥锁) | |
| F_UNLCK:解锁 | |
| L_start | 加锁区域在文件中的相对位移量(字节),与l_whence值一起决定加锁区域的起始位置 | 
| l_whence | SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小 | 
| SEEK_CUR:当前位置为文件指针的位置,新位置为当前位置加上偏移量 | |
| SEEK_END:当前位置为文件的结尾,新位置为文件的长度加上偏移量的大小 | |
| L_len | 加锁区域的长度 | 
| L_pid | 具有阻塞当前进程的锁,其持有进程的进程号存放在l_pid,仅由F_GETLK返回 | 
2.5、文件的关闭
| 头文件 | #include <unistd.h> | |
| 函数原型 | int close(int fd); | |
| 作用 | 关闭指定的文件流 | |
| 参数 | fd | 文件描述符 | 
| 返回值 | 成功 | 0 | 
| 失败 | -1 | |
2.6、获取文件或目录的属性信息
//文件属性信息结构体
struct stat
{
    dev_t st_dev;               //device 文件的设备编号
    ino_t st_ino;               //inode 文件的i-node
    mode_t st_mode;             //protection 文件的类型和存取的权限
    nlink_t st_nlink;           //number of hard links 连到该文件的硬连接数目, 刚建立的文件值为1.
    uid_t st_uid;               //user ID of owner 文件所有者的用户识别码 
    gid_t st_gid;               //group ID of owner 文件所有者的组识别码 
    dev_t st_rdev;              //device type 若此文件为装置设备文件, 则为其设备编号 
    off_t st_size;              //total size, in bytes 文件大小, 以字节计算 
    blksize_t st_blksize;       //blocksize for filesystem I/O 文件系统的I/O 缓冲区大小. 
    blkcnt_t st_blocks;         //number of blocks allocated 占用文件区块的个数, 每一区块大小为512 个字节. 
    time_t st_atime;            //time of lastaccess 文件最近一次被存取或被执行的时间, 一般只有在用mknod、 utime、read、write 与tructate 时改变.
    time_t st_mtime;            //time of last modification 文件最后一次被修改的时间, 一般只有在用mknod、 utime 和write 时才会改变
    time_t st_ctime;            //time of last change i-node 最近一次被更改的时间, 此参数会在文件所有者、组、 权限被更改时更新 
};
st_mode参数定义了下列数种情况:
1、S_IFMT 0170000 文件类型的位遮罩 
2、S_IFSOCK 0140000 scoket
3、S_IFLNK 0120000 符号连接 
4、S_IFREG 0100000 一般文件 
5、S_IFBLK 0060000 区块装置 
6、S_IFDIR 0040000 目录 
7、S_IFCHR 0020000 字符装置 
8、S_IFIFO 0010000 先进先出 
9、S_ISUID 04000 文件的 (set user-id on execution)位 
10、S_ISGID 02000 文件的 (set group-id on execution)位 
11、S_ISVTX 01000 文件的sticky 位 
12、S_IRUSR (S_IREAD) 00400 文件所有者具可读取权限 
13、S_IWUSR (S_IWRITE)00200 文件所有者具可写入权限 
14、S_IXUSR (S_IEXEC) 00100 文件所有者具可执行权限 
15、S_IRGRP 00040 用户组具可读取权限 
16、S_IWGRP 00020 用户组具可写入权限 
17、S_IXGRP 00010 用户组具可执行权限 
18、S_IROTH 00004 其他用户具可读取权限 
19、S_IWOTH 00002 其他用户具可写入权限 
20、S_IXOTH 00001 其他用户具可执行权限上述的文件类型在 POSIX 中定义了检查这些类型的宏定义 
21、S_ISLNK (st_mode) 判断是否为符号连接 
22、S_ISREG (st_mode) 是否为一般文件 
23、S_ISDIR (st_mode) 是否为目录 
24、S_ISCHR (st_mode) 是否为字符装置文件 
25、S_ISBLK (s3e) 是否为先进先出 
26、S_ISSOCK (st_mode) 是否为socket 若一目录具有sticky 位 (S_ISVTX), 则表示在此目录下的文件只能 被该文件所有者、此目录所有者或root 来删除或改名.
函数失败时对应的错误代码:
1、ENOENT 参数file_name 指定的文件不存在 
2、ENOTDIR 路径中的目录存在但却非真正的目录
3、ELOOP 欲打开的文件有过多符号连接问题, 上限为16 符号连接
4、EFAULT 参数buf 为无效指针, 指向无法存在的内存空间
5、EACCESS 存取文件时被拒绝
6、ENOMEM 核心内存不足
7、ENAMETOOLONG 参数file_name 的路径名称太长
| 头文件 | #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> | |
| 函数原型 | int stat(const char *path, struct stat *buf); //获取未打开文件的属性 int fstat(int fd, struct stat *buf); //获取打开文件的属性 int lstat(const char *path, struct stat *buf); //该函数类似于stat,但是当命名的文件为一个符号链接时,该函数返回的是符号连接的信息,而不是由该符号连接引用的文件的信息。 | |
| 作用 | 获取文件或目录的属性 | |
| 参数 | path | 文件路径,包括文件名 | 
| fd | 文件描述符 | |
| buf | 存放文件信息 | |
| 返回值 | 成功 | 0 | 
| 失败 | 失败返回-1,错误代码存于errno | |
3、FILE文件指针和文件描述符的相互转换
创建套接字时返回文件描述符,而为了使用标准I/O函数,只能将其转换为FILE结构体指针。先介绍其转换方法:
| 头文件 | #include <stdio.h> | |
| 函数原型 | FILT * fdopen(int fd, const char * mode); | |
| 作用 | 将文件描述符转换成文件指针 | |
| 参数 | fd | 需要转换的文件描述符 | 
| mode | 将要创建的FILE结构体指针的读写模式信息,fopen函数中的打开模式相同,常用的参数有读模式“r”和写模式“w”。 | |
| 返回值 | 成功 | 返回转换后的FILE结构体指针 | 
| 失败 | 返回NULL | |
| 头文件 | #include <stdio.h> | |
| 函数原型 | FILT * fileno(FILE * stream); | |
| 作用 | 将FILE文件指针转换成文件描述符 | |
| 参数 | stream | FILE文件指针 | 
| 返回值 | 成功 | 返回转换后的文件描述符 | 
| 失败 | 返回-1 | |
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号