本文个人在深圳吃饭的时候突然想到的...近期就有想写几篇关于文件返回的条记,所以回家到之后就奋笔疾书的写出来发布了
文件I/O
经常使用函数:
<fcntl.h>
1
|
int open(const char *pathname, int oflag, ... /* mode_t mode */);
|
打开或创建一个文件。第一个参数是文件的名字,第二个参数是选项,在O_RDONLY / O_WRONLY / O_RDWR 中选择一个打开的方式,然后可以用或运算指定额外的一些选项(例如O_APPEND写时追加到文件 尾,O_CREAT若文件不存在则创建,O_TRUNC文件截短为0等),第三个参数是创建新文件的访问权限位。返回值是以后最小的未用文件描述符,用于 该文件,出错返回-1。
1
|
int creat(const char *pathname, mode_t mode);
|
创建一个新文件,等效于 open(pathname, O_WRONLY | O_CREATE | O_TRUNC, mode);
1
|
int fcntl(int filedes, int cmd, ... /* int arg */ );
|
转变一个文件的性质。其中cmd的选项包含:F_DUPFD(复制一个现有的描述符,第三个参数为描述符数值的下限)、F_GETFD(获得文件描述符标 志)、F_SETFD(设置文件描述符标记,值为第三个参数)、F_GETFL(获得文件状态标记,可以与O_ACCMODE进行与运算,然后与三种访问 方式标记比较,可以与其他标记进行与运算判断标记位的存在)、F_SETFL(设置文件状态标记,设置为第三个参数,平日先获得现有的标记,然后用或运算 添加标记,用补码的与运算删除标记)、F_GETOWN、F_SETOWN(异步I/O全部权)、F_GETLK、F_SETLK、F_SETLKW(记 录锁)。出错返回-1。
罕见的用法:(错误处理略去)val = fcntl(fd, F_GETFL, 0); val |= flags; fcntl(fd, F_SETFL, val);
<unistd.h>
1
|
int close(int filedes);
|
根据文件描述符filedes关闭已打开的该文件并释放该进程加在该文件上的全部记录锁,胜利返回0,出错返回-1。
1
|
off_t lseek(int filedes, off_t offset, int whence);
|
为一个打开的文件设置偏移量,whence可以取SEEK_SET(距离文件开始处offset字节)、SEEK_CUR(以后值加offset)、SEEK_END(文件长度加offset),胜利时返回新的文件偏移量,出错返回-1。
1
|
ssize_t read(int filedes, void *buf, size_t nbytes);
|
从filedes引用的文件中读取nbytes个字节到buf所指向的内存空间中。胜利返回读到的字节数,达到文件尾返回0,出错返回-1。
罕见的用法:while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0) {...}
1
|
ssize_t write(int filedes, void *buf, size_t nbytes);
|
把buf所指的内存内容的count个字节写到filedes所引用的文件内。胜利返回写的字节数,出错返回-1。
罕见的用法:if (write(STDOUT_FILENO, buf, n) == n) {...}
1
|
ssize_t pread(int filedes, void *buf, size_t nbytes, off_t offset);
|
带偏移量地读取数据,不会转变文件偏移指针位置,这里偏移操纵和读取操纵是一个原子操纵。
1
|
ssize_t pwrite(int filedes, void *buf, size_t nbytes, off_t offset);
|
同上,带偏移量地写数据。
1
|
int dup(int filedes);
|
复制文件描述符filedes,使以后可用文件描述符中最小的描述符与filedes共享一个文件表项,然后返回这一新的描述符,出错返回-1。
1
|
int dup2(int filedes, int filedes2);
|
复制文件描述符filedes,使当文件描述符filedes2与filedes共享一个文件表项。如果filedes2已经打开,则先关闭,这里关闭操纵 与描述符的复制操纵是一个原子操纵。如果filedes与filedes2相等,不做任何事。胜利则返回filedes2,出错返回-1。
1
2
3
|
void sync(void);
int fsync(int filedes);
int fdatasync(int filedes);
|
将系统缓冲区的内容写回磁盘确保数据同步。第二个函数只对单一文件作用。第三个函数只对文件的数据部分作用,不影响文件属性。
细节:
与标准输入、标准输出、标准出错关联的文件描述符分别是STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO。
.和..并不总是两个目录,对于根目录来说它们是相同的。
创建文件的函数是creat()而不是create()。
使用O_APPEND标记打开一个文件后,仍可以用lseek在任意位置开始读,但不能用lseek在任意位置写入。
./a.out > outfile 2>&1 : 执行后1和2都指向outfile
./a.out 2>&1 > outfile : 执行后只有1指向outfile
dup和dup2例子解释:
//声明及异常处理代码略去
1
2
3
4
5
6
7
8
|
fd = open("somefile", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
save_fd = dup(STDOUT_FILENO);
dup2(fd, STDOUT_FILENO);
close(fd);
write(STDOUT_FILENO, msg, strlen(msg));
dup2(save_fd, STDOUT_FILENO);
write(STDOUT_FILENO, msg, strlen(msg));
close(save_fd);
|
具体执行细节如图所示:
两处重点:
第3幅图,要执行dup2(fd, 1);,文件描述符1原本指向tty,现在要指向新的文件somefile,就把原来的关闭了,但是tty这个文件原本有2个引用计数,还有文件描述符save_fd也指向它,所以只是将引用计数减1,并不真的关闭文件。
第5幅图,要执行dup2(save_fd, 1);,文件描述符1原本指向somefile,现在要指向新的文件tty,就把原来的关闭了,somefile原本只有1个引用计数,所以这次减到0,是真的关闭了。
文件和目录
经常使用函数:
<sys/stat.h>
1
2
3
|
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);
|
将文件有关的信息结构通过参数buf返回。胜利返回0,出错返回-1。
stat和lstat通过路径获取,fstat通过文件描述符获取。如果文件是一个符号链接,lstat返回该符号链接的信息而不是链接指向文件的信息。
1
|
mode_t umask(mode_t cmask);
|
设置文件模式创建屏蔽字,并返回之前的值,没有出错返回。参数是由S_IRUSR、S_IWUSR、S_IXUSR、S_IRGRP、S_IWGRP、S_IXGRP、S_IROTH、S_IWOTH、S_IXOTH中的若干位或运算构成的。
1
2
|
int chmod(const char *pathname, mode_t mode);
int fchmod(int filedes, mode_t mode);
|
更改文件的访问权限,这里的参数mode除了umask的9个之外还有6个:S_ISUID、S_ISGID、S_ISVTX、S_IRWXU、S_IRWXG、S_IRWXO。
1
2
|
int mkdir(const char *pathname, mode_t mode);
int rmdir(const char *pathname);
|
创建和删除目录。胜利返回0,出错返回-1。
<unistd.h>
1
|
int access(const char *pathname, int mode);
|
测试对文件的访问能力,mode可以取R_OK、W_OK、X_OK、F_OK,分别测试读、写、执行的权限以及文件是否存在。胜利返回0,出错返回-1。
1
2
3
|
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char *pathname, uid_t owner, gid_t group);
|
更改文件的用户ID和组ID。对于符号链接,lchown修改的是符号链接本身的信息而不是指向文件的信息。胜利返回0,出错返回-1。
1
2
|
int truncate(const char *pathname, off_t length);
int ftruncate(int filedes, off_t length);
|
将文件截短为length字节。胜利返回0,出错返回-1。
1
|
int link(const char *existingpath, const char *newpath);
|
创建一个新目录项newpath,它引用现有的文件existingpath。胜利返回0,出错返回-1。
1
|
int unlink(const char *pathname);
|
删除目录项,并使其所引用文件的链接计数减1。胜利返回0,出错返回-1。
1
|
int symlink(const char *actualpath, const char *sympath);
|
创建符号链接:指向actualpath的新目录项sympath。胜利返回0,出错返回-1。
1
|
ssize_t readlink(const char *restrict pathname, char *restrict buf, size_t bufsize);
|
打开符号链接本身进行读取,胜利返回读的字节数,出错返回-1。
1
2
|
int chdir(const char *pathname);
int fchdir(int filedes);
|
更改以后工作目录。胜利返回0,出错返回-1。
1
|
char *getcwd(char *buf, size_t size);
|
获取以后工作目录的绝对路径,胜利返回buf,出错返回空指针。
<stdio.h>
1
|
int remove(const char *pathname);
|
对于文件,remove的功能与unlink相同,对于目录,remove的功能与rmdir相同。胜利返回0,出错返回-1。
1
|
int rename(const char *oldname, const char *newname);
|
为文件或目录更名。胜利返回0,出错返回-1。
<utime.h>
1
|
int utime(const char *pathname, const struct utimbuf *times);
|
修改文件的访问时间(atime)和修改时间(mtime),其中utimbuf的结构包含actime和modtime两个成员。调用utime时,文件的更改状态时间(ctime)自动更新。胜利返回0,出错返回-1。
<dirent.h>
1
|
DIR *opendir(const char *pathname);
|
打开一个目录,失败时返回空指针。
1
|
struct dirent *readdir(DIR *dp);
|
读取目录一次,返回目录中下一个dirent结构体指针,顺序与实现有关,失败时返回空指针。
1
|
void rewinddir(DIR *dp);
|
将目录的读取位置重置为开头。
1
|
int closedir(DIR *dp);
|
关闭参数dir所指的目录,胜利返回0,出错返回-1。
1
|
long telldir(DIR *dp);
|
返回目录读取的以后位置偏移量,出错返回-1。
1
|
void seekdir(DIR *dp, long loc);
|
设置参数dir目录流目前的读取位置。
细节:
文件的信息用stat结构保存,可以用lstate函数获取。
文件的类型信息保存在stat结构的st_mode成员中,可以用S_ISREG(),S_ISDIR(),S_ISLNK()等宏进行判断。
文件的全部者和全部组用stat结构中的st_uid和st_gid成员表示。
文件是否有SUID和SGID属性可以用S_ISUID和S_ISGID测试。
对于umask中为1的位,在文件的mode中相应位(S_IR/W/XUSR/GRP/OTH)一定被关闭。
SUID,SGID,SBIT对应的mode中的位分别是S_ISUID,S_ISGID,S_ISVTX(saved-text bit)。
创建符号链接时,可以指向一个不存在的文件。
普通文件的长度可以是0。目录的长度不会是0,因为至少包含.和..两项。符号链接的长度是路径名中的实际字节数,也不会是0。
dirent结构中表示文件名的成员是d_name。
标准I/O库
经常使用函数:
<stdio.h>
1
|
void setbuf(FILE *restrict fp, char *restrict buf);
|
打开或关闭缓冲机制。如果buff非空,则fp的缓冲为长度为BUFSIZ的缓冲buf,如果buff为空,则fp为无缓冲。
1
|
int setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);
|
精确指定缓冲类型。mode参数可选_IOFBF(长度为size的用户buf全缓冲,buff为空则自动分配)、_IOLBF(长度为size的用户buf行缓冲,buff为空则自动分配)、_IONBF(无缓冲,忽略buf和size)。
1
|
int fflush(File *fp);
|
强制冲洗一个流,该流全部未写的数据都传送至内核。
1
2
3
|
FILE *fopen(const char *restrict pathname, const char *restrict type);
FILE *freopen(const char *restrict pathname, const char *restrict type, FILE *restrict fp);
FILE *fdopen(int filedes, const char *type);
|
fopen 打开一个指定的文件;freopen在指定的流上打开文件,若该流已经定向则先清除;fdopen打开一个现有的文件描述符,并与一个标准的I/O流结 合。参数type指定读写方式:r或rb(读,文件必须已存在)、w或wb(删除之前的内容,写)、a或ab(在文件末尾写)、r+或r+b或rb+(读 写,文件必须已存在)、w+或w+b或wb+(删除之前的内容,读写)、a+或a+b或ab+(读写,只能在末尾写)。胜利返回文件指针,出错返回空指 针。
1
|
int fclose(FILE *fp);
|
关闭一个打开的流。胜利返回0,出错返回EOF。
1
2
3
|
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
|
一次读一个字符。getc可被实现为宏,fgetc不能被实现为宏。getchar等价于getc(stdin)。胜利返回下一个字符,达到文件结尾或出错返回EOF。
罕见的用法:while ((c = getc(stdin)) != EOF) {...}
1
|
int ungetc(int c, FILE *fp);
|
将字符压回流中。胜利返回c,出错返回EOF。
1
2
3
|
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);
|
一次输出一个字符,其之间区别与getc函数类似。胜利返回c,出错返回EOF。
1
2
|
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *buf);
|
每次读入一行到缓冲区buf,gets从标准输入读,fgets从指定的流读。fgets读到换行符为止,但是不超过n-1个字符,放入buf后以null字符结尾。gets有可能造成缓冲区溢出。胜利返回buf,达到文件尾或出错返回EOF。
罕见的用法:while (fgets(buf, MAXLINE, stdin) != NULL) {...}
1
2
|
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);
|
每次输出一行。尾端的null字符不输出。胜利返回非负值,出错返回EOF。
1
2
|
int ferror(FILE *fp);
int feof(FILE *fp);
|
检查是否出错/是否达到文件尾,返回一个非0值表示真,返回0表示假。
1
2
|
size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
|
二进制读写,size为每个元素的长度,nobj为要读写的元素个数。返回读或写的元素个数。
罕见的用法:float data[10]; if (fwrite(&data[2], sizeof(float), 4, fp) != 4) {/*error*/}
1
|
long ftell(FILE *fp);
|
胜利返回以后文件位置指示,出错返回-1L。
1
|
int fseek(FILE *fp, long offset, int whence);
|
胜利返回非0值,出错返回0。
二进制文件的字节位置,whence的取值可以有SEEK_SET、SEEK_CUR和SEEK_END。
1
2
|
off_t ftello(FILE *fp);
int fseeko(FILE *fp, off_t offset, int whence);
|
与ftell和fseek对比,只是返回值类型不同。
1
2
|
int fgetpos(FILE *restrict fp, fpos_t *restrict pos);
int fsetpos(FILE *fp, const fpos_t *pos);
|
文件位置标记使用fpos_t结构存放。
1
2
3
4
|
int printf(const char *restrict format, ...);
int fprintf(FILE *restrict fp, const char *restrict format, ...);
int sprintf(char *restrict buf, const char *restrict format, ...);
int snprintf(char *restrict buf, size_t n, const char *restrict format, ...);
|
printf将格式化数据写到标准输出;fprintf写到指定的流;sprintf将格式化的字符送入数组buf;snprintf超过缓冲区长度的字符会被丢弃。
printf和fprintf胜利返回输出字符数,出错返回负值。sprintf和snprintf胜利返回存入数组的字符数,出错返回负值。
1
2
3
|
int scanf(const char *restrict format, ...);
int fscanf(FILE *restrict fp, const char *restrict format, ...);
int sscanf(const char *restrict buf, const char *restrict format, ...);
|
格式化输入。返回输入项数,出错或达到文件尾返回EOF。
1
|
int fileno(FILE *fp);
|
获得一个流的文件描述符。
1
|
char *tmpnam(char *ptr);
|
产生一个与现有文件名不同的有效路径名字符串,返回路径名的指针。
1
|
FILE *tmpfile(void);
|
创建一个临时二进制文件,在关闭文件或程序结束时自动删除。胜利返回文件指针,失败返回NULL。
细节:
默认情况下,标准出错是不带缓冲的,打开至终端设备的流是行缓冲的,其他流是全缓冲的。
只有两个函数可以转变流的定向:freopen函数清除流的定向,fwide函数设置流的定向。
printf不输出字符时,例如printf("");返回0。
对标准I/O流使用fsync函数,先调用fflush,将数据从内存缓冲区传至内核,然后通过fileno获得fsync的参数。
系统数据文件和信息
经常使用函数:
<pwd.h>
1
2
|
struct passwd *getpwuid(uid_t uid);
struct passwd *getpwnam(const char *name);
|
根据用户ID或者用户名获取用户对应的passwd结构(登录相关信息),出错返回NULL。
1
2
3
|
struct passwd *getpwent(void);
void setpwent(void);
void endpwent(void);
|
getpwent打开口令文件(第一次调用时),读取口令文件中的下一个记录项,每调用一次返回一个记录项,出错或达到文件结尾时返回NULL。setpwent重置读取口令文件的位置。endpwent关闭口令文件。
<shadow.h>
1
2
3
4
|
struct spwd *getspnam(const char *name);
struct spwd *getspent(void);
void setspent(void);
void endspent(void);
|
访问阴影口令文件。
<grp.h>
1
2
3
4
5
|
struct group *getgrgid(gid_t gid);
struct group *getgrnam(const char *name);
struct group *getgrent(void);
void setgrent(void);
void endgrent(void);
|
访问组信息。
<time.h>
1
|
time_t time(time_t *calptr);
|
返回以后时间和日期,如果参数不为空,也存放在calptr指向的内存中。出错返回-1。
<sys/time.h>
1
|
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
|
返回0,以后时间存放在tp指向的内存中,tzp参数取NULL。timeval结构包含两个成员,time_t tv_sec存放秒,long tv_usec存放微秒。
细节:
口令文件是/etc/passwd,包含用户登录的信息,但不包含口令。
口令加密后存放在阴影文件/etc/shadow中。
组信息存放在/etc/group中。
文章结束给大家分享下程序员的一些笑话语录: 问:你觉得让你女朋友(或者任何一个女的)从你和李彦宏之间选一个,你觉得她会选谁?
答:因为李艳红这种败类,所以我没女友!
--------------------------------- 原创文章 By
文件和返回
---------------------------------