文件返回UNIX环境高级编程学习笔记(上)

本文个人在深圳吃饭的时候突然想到的...近期就有想写几篇关于文件返回的条记,所以回家到之后就奋笔疾书的写出来发布了

    

文件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
文件和返回
---------------------------------

原文地址:https://www.cnblogs.com/jiangu66/p/3102298.html