LINUX/UNIX的文件操作函数

本文用于记录在LINUX编程中,常用的文件操作函数,包括系统调用和库函数,以备查阅。

针对输入输出操作,直接使用底层系统调用的一个问题是它们的效率十分低,原因在于:

1.使用系统调用会影响系统的性能,与函数调用相比,系统调用的开销要大些,因为在执行系统调用时,Linux必须从运行用户代码切换到执行内核代码,然后再返回用户代码。 
2.硬件会限制对底层系统调用一次所能读写的数据块大小。比如,磁带机通常一次能写的数据块长度是10K,所以若你试图写的数据量不是10K的整数倍,磁带机还是以10K为单位卷绕磁带,从而在磁带上留下空隙


#include <unistd.h>
size_t write(int fildes, const void *buf, size_t nbytes);

系统调用write作用:把缓冲区buf的前nbytes个字节写入与文件描述符fildes关联的文件中。它返回实际写入的字节数,若文件描述符有错或底层的设备驱动程序对数据块长度比较敏感,该返回值可能会小于nbytes。如果函数返回0,就表示未写入任何数据;如果返回-1,就表示write调用中出现了错误,错误代码保存在全局变量errno里。


#include <unistd.h>
size_t read(int fildes, void *buf, size_t nbytes);

系统调用read作用:从与文件描述符fildes关联的文件里读入nbytes个字节的数据,并把它们放到数据区buf中。它返回实际读入的字节数,该返回值可能会小于请求的字节数。如果函数返回0,就表示未读入任何数据,已到达文件尾。如果返回-1,就表示read调用中出现了错误,错误代码保存在全局变量errno里。


#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode);

系统调用open作用:调用成功返回一个唯一的新文件描述符(总是一个非负整数),失败时返回-1并设置全局变量errno。准备打开的文件或设备的名字作为参数path传递给函数,oflags参数用于指定打开文件所采取的动作。oflags可选参数如下:


当使用带有O_CREAT标志的open调用来创建文件时,必须使用有3个参数格式的open调用,其中第三个参数mode有以下标志位:

以上这些标志位在头文件sys/stat.h中定义


#include <unistd.h>
int close(int fildes);

终止文件描述符fildes与其对应文件之间的关联。文件描述符被释放并能够重新使用。close调用成功时返回0,出错时返回-1


#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fildes, off_t offset, int whence);

offset参数用来指定位置,而whence参数定义偏移值,whence可以取下列值:


lseek返回从文件头到文件指针被设置处的字节偏移值,失败时返回-1。


#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int fstat(int fildes, struct stat *buf);
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);

fstat系统调用返回与打开的文件描述符相关的文件的状态信息,该信息将会写入到一个buf结构中,buf的地址以参数形式传递给fstat
相关函数stat和lstat返回的是通过文件名查到的状态信息。它们产生相同的结果,但当文件是一个符号链接时,lstat返回的是该符号链接本身的信息,而stat返回的是该链接指向的文件的信息。
stat结构一般包括如下成员:


stat结构中返回的st_mode标志还有一些与之关联的宏,它们定义在sys/stat.h中。
这些宏包括对访问权限、文件类型标志以及一些用于帮助测试特定类型和权限的掩码的定义。



#include <unistd.h>
int dup(int fildes);
int dup2(int fildes, int fildes2);

dup系统调用提供一种复制文件描述符的方法,使我们能够通过两个或更多个不同的描述符来访问同一个文件。这可以用于在文件的不同位置对数据进行读写。dup系统调用复制文件描述符fildes,返回一个新的描述符。dup2系统调用则是通过明确指定目标描述符来把一个文件描述符复制为另外一个。


#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);

fopen库函数类似于底层的open系统调用。它主要用于文件和终端的输入输出。如果需要对设备进行明确的控制,则最好使用系统调用,因为这可以避免用库函数带来的一些潜在问题,如输入/输出缓冲。
fopen打开由filename参数指定的文件,并把它与一个文件流关联起来。mode参数指定文件的打开方式,它取下列字符串中的值:


fopen在成功时返回一个非空的FILE*指针,失败时返回NULL值,NULL值在stdio.h中定义


#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);

fread库函数用于从一个文件流里读取数据。数据从文件流stream读到由ptr指向的数据缓冲区里。size参数指定每个数据记录的长度,计数器nitems给出要传输的记录个数。它的返回值是成功读到数据缓冲区里的记录个数(而不是字节数)。当到达文件尾时,它的返回值可能会小于nitems,甚至可以是零。


#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);

fwrite库函数用于从指定的数据缓冲区里取出数据记录,并把它们写到输出流中。size参数指定每个数据记录的长度,计数器nitems给出要写的记录个数。它的返回值是成功写入的记录个数(而不是字节数)。当到达文件尾时,它的返回值可能会小于nitems,甚至可以是零。


#include <stdio.h>
int fclose(FILE *stream);

fclose库函数关闭指定1文件流stream,使所有尚未写出的数据都写出。因为stdio库会对数据进行缓冲,所以使用fclose很重要。当程序正常结束时,会自动对所有还打开的文件流调用fclose函数


#include <stdio.h>
int fflush(FILE *stream);

fflush库函数的作用是把文件流里的所有未写出数据立刻写出。需要注意的是,fclose函数隐含的调用fflush,所以不必调用fclose之前调用fflush。


#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence);

fseek函数是与lseek系统调用对应的文件流函数,它在文件流里为下一次读写操作指定位置。offset和whence参数的含义与取值与lseek系统调用完全一样,但lseek返回的是一个off_t数值,而fseek返回的是一个整数,0表示成功,-1表示失败并设置errno指出错误。


#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar();

fgetc函数从文件流里取出下一个字节并把它作为一个字符返回。当它到达文件尾或出现错误时,它返回EOF。而必须通过ferror或feor函数来区分这两种情况。getc函数的作用于fgetc一样,但它有可能被实现为一个宏。而getchar函数则相当于getc(stdin),它从标准输入里读取下一个字符。


#include <stdio.h>
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar();

这三个函数关系与上述三个函数关系类似,putchar相当于putc(c, stdout),它把单个字符写到标准输出。需要注意的是,putchar和getchar都是把字符当做int类型而不是char类型来使用,这就允许文件尾(EOF)标识取值-1,这是一个超出字符数字编码范围的值。


#include <stdio.h>
char *fgets(char *s, int n, FILE *stream);
char *gets(char *s);

fgets函数从输入文件流stream里读取一个字符串到s指向的字符串里,直到出现下面某种情况:遇到换行符,已经传输了n-1个字符,或者到达文件尾。它会把遇到的换行符也传递到接收字符串里,再加上一个表示结尾的空字节\0。一次调用最多只能传输n-1个字符,因为它必须把空字节加上以结束字符串。当调用成功返回一个指向字符串s的指针。如果文件流已经到达文件尾,fgets会设置这个文件流的EOF标识并返回一个空指针。如果出现读错误,fgets返回一个空指针并设置errno以指出错误的类型。
gets函数类似fgets,但它从标准输入读取数据并丢弃遇到的换行符。它在接收字符串的尾部加上一个nul字节。需要注意的是,gets对传输字符的个数并没有限制,所以它可能会溢出自己的传输缓冲区。


#include <stdio.h>
int fputs(const char * s, FILE * stream); 
int puts(const char *string);

fputs函数将参数s所指的字符串写到输出文件流stream中,若调用成功则返回写出的字符个数,如果返回EOF表示发生写错误。
puts函数类似fputs,它将参数s所指的字符串输出到标准输出中。它遇到空字节\0才会停止输出。并且在输出完字符串后会自动输出一个换行符\n


#include <stdio.h>
int printf(const char * format, ...); 
int sprintf(char *s, const char * format, ...); 
int fprintf(FILE *stream, const char * format, ...); 

printf函数把自己的输出送到标准输出。fprintf函数则把自己的输出送到一个指定的文件流。sprintf函数把自己的输出和一个结尾空字符写到作为参数传递过来的字符串s里。这个字符串必须足够容纳所有的输出数据。


#include <stdio.h>
int scanf(const char * format, ...); 
int sscanf(const char *s, const char * format, ...); 
int fscanf(FILE *stream, const char * format, ...); 

scanf函数读入的值保存到对应的变量里去,这些变量的类型必须正确,并且它们必须准确匹配格式字符串。否则内存数据就可能会遭到破坏,从而使程序崩溃。scanf系列函数的format格式字符串里同时包含着普通字符和转换控制符,那些普通字符是用于指定在输入数据里必须出现的字符。
例如 scanf ("Hello %d", &num);
则这个scanf调用只有在标准输入中接下来的五个字符匹配"Hello"的情况下才会成功。
scanf函数1返回值是它成功读取的数据项个数,如果在读第一个数据项时失败了,则它的返回值是零。如果在匹配第一个数据项之前就已经到达了输入的结尾,它就会返回EOF。如果文件流发送读错误,流错误标志就会被设置并且错误变量errno将被设置以指明错误类型。


#include <errno.h>
extern int errno;

许多函数都可能改变errno的值,它的值只有在函数调用失败时才有意义。必须在函数表明失败之后立刻对其进行检查。使用之前应该将它先复制到另一个变量中,因为像fprintf这样的输出函数本身就可以改变errno的值,也可以通过检查文件流的状态来确定是否发生了错误,或者是否到达了文件尾。关于错误代码的取值和含义都列在头文件errno.h中,一般包括:

#include <string.h>
char *strerror(int errnum);

strerror函数把错误代码映射为一个字符串,该字符串对发生的错误类型进行说明。


#include <stdio.h>
void perror(const char *s);

perror函数也把errno变量中报告的当前错误映射为一个字符串,并把它输出到标准错误输出流。该字符串的前面先加上字符串s(如果不为空)中给出的信息,再加上一个冒号和一个空格。


#include <stdio.h>
int ferror(FILE *stream); 
int feof(FILE *stream); 
void clearerr(FILE *stream);

ferror函数测试一个文件流的错误标识,如果该标识被设置就返回一个非零值,否则返回0。
feof函数测试一个文件流的文件尾标识,如果该标识被设置就返回一个非零值,否则返回0。
clearerr函数的作用是清除由stream指向的文件流的文件尾标识和错误标识。它没有返回值,也未定义任何错误。


#include <stdio.h>
int fileno(FILE *stream);
FILE *fdopen(int fildes, const char *mode);

可以通过调用fileno函数来确定文件流使用的是哪个底层文件操作符。它返回指定文件流使用的文件描述符,如果失败则返回-1。
可以通过调用fdopen函数在一个已打开的文件描述符上创建一个新的文件流,实质上,该函数作用是为一个已经打开的文件描述符提供stdio缓冲区。


#include <sys/stat.h>
int chmod(const char *path, mode_t mode);

chmod系统调用用来改变文件或目录的访问权限。参数mode的定义与open系统调用一样。


#include <sys/types.h>
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);

chmod系统调用用来改变一个文件的属主。调用使用的是用户ID和组ID的数字值(通过getuid和getgid调用获得)


#include <unistd.h>
int unlink(const char *path);
int link(const char *path1, const char *path2);
int symlink(const char *path1, const char *path2);

unlink系统调用删除一个文件的目录项并减少它的链接数。成功时返回0,失败时返回-1。若要用该系统调用来成功删除文件,必须拥有该文件所属目录的写和执行权限。如果一个文件的链接数减少到零,并且没有进程打开它,这个文件就会被删除。
使用link系统调用在程序中创建一个文件的新链接。它将创建一个指向已有文件path1的新链接,新目录项由path2给出。
使用symlink系统调用以类似的方法创建符号链接,注意,一个文件的符合链接并不会增加该文件的链接数。


#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char *path, mode_t mode);

mkdir系统调用用于创建目录,它将参数path作为新建目录的名字。目录的权限由参数mode设定,其含义将按open系统调用的O_CREAT选项中的有关定义设置。当然还需要服从umask的设置情况。


#include <unistd.h>
int rmdir(const char *path);

rmdir系统调用用于删除目录,但只有在目录为空时才行。


#include <unistd.h>
int chdir(const char *path);

chdir系统调用用于改变工作目录。


#include <unistd.h>
char *getcwd(char *buf, size_t size);

getcwd系统调用用于把当前目录的名字写到给定的缓冲区buf里。如果目录名的长度超出了参数size给出的缓冲区长度(一个ERANGE错误),它就返回NULL,如果成功,它返回指针buf。需要注意的是,如果程序运行过程中,目录被删除(EINVAL错误)或者有关权限发生了变化(EACCESS错误),getcwd也可能会返回NULL。


#include <sys/types.h>
#Include <dirent.h>
DIR *opendir(const char *name);

opendir函数的作用是打开一个目录并建立一个目录流。如果成功,它返回一个指向DIR结构的指针,该指针用于读取目录数据项。opendir在失败时返回一个空指针(NULL)。


#include <sys/types.h>
#Include <dirent.h>
struct dirent *readdir(DIR *dirp);

readdir函数返回一个指针,该指针指向的结构里保存着目录流dirp中下一个目录项的有关资料。后续的readdir调用将返回后续的目录项。如果发生错误或到达目录尾,readdir将返回NULL。当到达目录尾时会返回NULL,但并不改变errno的值,只有在发生错误时才会设置errno。需要注意的是,如果在readdir函数扫描目录的同时还有其他进程在该目录里创建或删除文件,readdir将不保证能够列出该目录里的所有文件(和子目录)。


#include <sys/types.h>
#Include <dirent.h>
long int telldir(DIR *dirp);

telldir函数的返回值记录着一个目录流里的当前位置。


#include <sys/types.h>
#Include <dirent.h>
void seekdir(DIR *dirp, long int loc);

seekdir函数的作用是设置目录流dirp的目录项指针。loc的值用来设置指针位置,它通过telldir调用获得。


#include <sys/types.h>
#Include <dirent.h>
int closedir(DIR *dirp);

closedir函数的作用是关闭一个目录流并释放与之关联的资源。执行成功返回0,发生错误时返回-1。


其他流函数:

int fgetpos( FILE *stream, fpos_t *pos );
获得文件流的当前(读写)位置

int fsetpos(FILE *fp, const fpos_t *pos);
设置文件流的当前(读写)位置

long ftell(FILE *fp);
返回文件流的当前(读写)位置的偏移值

void rewind(FILE *stream);
rewind:重置文件流里的读写位置

FILE *freopen( const char *path, const char *mode, FILE *stream );
实现重定向,把预定义的标准流文件定向到由path指定的文件中。

void setbuf(FILE *stream,char *buf);
void setvbuf(FILE *stream,char *buf,int type,unsigned size);

设置文件流的缓冲机制,用户可建立自己的文件缓冲区,而不使用fopen()函数打开文件设定的默认缓冲区。对于setbuf()函数,buf指出的缓冲区长度由头文件stdio.h中定义的宏BUFSIZE的值决定,缺省值为512字节。当选定buf为空时,setbuf函数将使的文件I/O不带缓冲。而对setvbuf函数,则由malloc函数来分配缓冲区。参数size指明了缓冲区的长度(必须大于0),而参数type则表示了缓冲的类型,其值可以取如下值:
type 值 含义
  _IOFBF 文件全部缓冲,即缓冲区装满后,才能对文件读写
  _IOLBF 文件行缓冲,即缓冲区接收到一个换行符时,才能对文件读写
  _IONBF 文件不缓冲,此时忽略buf,size的值,直接读写文件,不再经过文件缓冲区缓冲

int remove(char *path);
相当于unlink函数,但如果它的path参数是一个目录,其作用则相当于rmdir函数


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值