在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
linux 文件I/O教程(1) 一,文件描述符 一般有三个以及打开的文件描述符,他们是: 复制代码 代码如下:0:标准输入 STDIN_FILENO 1:标准输出 STDOUT_FILENO 2标准错误输出 STDERR_FILENO 每行后面的符号常量是依从POSIX而定的。 复制代码 代码如下:#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, int flags,mode_t mode); pathname是要打开或创建文件的名字。 flag用来定义打开文件所采取的的动作,必须调用以下模式之一 open还可以包括以下可选模式的组合 open返回的文件描述符一定是最小的未用描述符数值。这一点被某些应用程序用在标准输入,标准输出或标准错误输出上。如,一个程序关闭了自己的标准输出,然后再次调用open,文件描述符1就会被调用,并且标准输出将被有效的重定向到另一个文件或设备。 POSIX规范还标准化了一个creat调用,此函数等效于 close函数 close调用终止一个文件描述符fd与对应文件之间的关联。文件描述符被释放后并能重新使用。close调用成功返回0,出错返回-1. 关闭一个文件时会释放该进程加在文件上的所有记录锁。当一个进程终止时,内核自动关闭它所有打开的文件。 lseek函数 复制代码 代码如下:#include <sys/types.h> #include <unistd.h> off_t lseek(int fd, off_t offset, intwhence); offset用来指定位置,whence参数定义该偏移值的用法。whence可取以下值: 复制代码 代码如下:SEEK_SET: The offset is set to offset bytes. SEEK_CUR: The offset is set to its current locationplus offset bytes. SEEK_END: The offset is set to the size of the fileplus offset bytes. 成功调用返回从文件头到文件指针被设置处的字节偏移值,失败返回-1。参数offset定义在<sys/types.h>中。 当偏移量大于文件长度时,出现空洞,空洞不占用存储区。 read函数 复制代码 代码如下:#include <unistd.h> ssize_t read(int fd, void *buf, size_tcount); 将与文件描述符fd关联的文件中读入count个字符放到buf中。返回读入的字节数,它可能小于请求的字节数。如果read调用返回0,就表示未读入任何数据,已到达了文件尾。返回-1,就表示出错。 write函数 复制代码 代码如下:#include <unistd.h> ssize_t write(int fd, const void *buf,size_t count); 把缓冲区buf的前count个字节写入与文件描述符fd相关联的文件中。返回实际写入的字节数,通常与count值相同;否则表示出错。出错的一个常见原因是:磁盘已写满,或者超出了一个给定进程的文件长度限制。 实例:创建一个文件,写入数据,移动当前偏移量,在读数据。 复制代码 代码如下:#include<unistd.h> //<unistd.h>必须最早出现,因为它可能会影响到其他头文件。#include<stdio.h> #include<fcntl.h> #include<string.h> #include<errno.h> int main() { char* filename = ".//file"; char buf[100]; char buf1[5]; int fd; printf("open a file to write\n"); if((fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH ))==-1) { perror("cannot open file\n"); return 1; } printf("open file successfully!\n"); printf("input a string:"); gets(buf); //write intofile if(write(fd,buf,strlen(buf)) !=strlen(buf)) { perror("cannot write intofile\n"); return 1; } close(fd); printf("open file to read.\n"); if((fd=open(filename,O_RDONLY)) == -1) { perror("cannot open thefile.\n"); return 1; } if(lseek(fd,3,SEEK_SET) == -1) { perror("lseek erroe\n"); return 1; } //read from the file if(read(fd,buf1,4)==-1) { perror("read error.\n"); return 1; } printf("read from file is%s\n",buf1); close(fd); return 0; } 执行与输出结果: 复制代码 代码如下:root@ogeek:~$gcc -o io io.c root@ogeek:~$./io open a file towrite open filesuccessfully! input a string:akxivbaslzkncxcasbxbwwvaidxbd open file toread. read from fileis ivba linux 文件I/O教程(2) 下面介绍了linux中有关文件I/O的相关内容,内核使用三种数据结构表示打开的文件,他们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。 一,文件共享 打开文件的内核数据结构 如果两个进程各自打开了同一个文件,则如图2所示。假定第一个进程在文件描述符3打开上该文件,而另一个进程在文件描述符4上打开该文件。每个进程都得得到一个文件表项,但对一个给定的文件只有一个v节点表项。每个进程都有自己的文件表项的一个理由是:使每个进程都有自己对该问价的当前偏移量。 现在对前一节文件I/O(1)的几个操作进一步说明: 可能有多个文件描述符指向同一文件表项。调用dup和fork时都能看到这一点。 原子操作 复制代码 代码如下:if(lseek(fd, 0L, 2)<0) err_sys(“lseekerror”); if(write(fd, buf, 100) != 100) err_sys(“writeerror”); 对于单个进程,这段程序能正常工作。但多个进程就不一定。结社进程A和B都对同一文件进行添加操作。每个进程都打开该文件,此时数据结构之间关系如图2中所示。假定A调用lseek,将A的当前偏移量设置为1500。进程B执行lseek也将其当前偏移量设为1500。然后B调用write,将当前偏移量增至1600。然后内核又进行进程切换使进程A恢复运行,当A调用write时,从其当前偏移量1500处将数据写入,将替换B刚写入到该文件中的数据。 问题出在逻辑操作“定位到文件尾端处,然后写“使用了两个分开的函数调用。解决办法是使这两个操作成为一个原子操作。O_APPEND标识,使内核每次对文件进行写之前,都将进程当前偏移量设置到该文件的尾端处。 2.pread和pwrite函数 复制代码 代码如下:#include <unistd.h> ssize_t pread(int fd, void *buf, size_tcount, off_t offset); ssize_t pwrite(int fd, const void *buf,size_t count, off_t offset); ssize_t pread(int fd, void *buf, size_tcount, off_t offset); ssize_t pwrite(int fd, const void *buf,size_t count, off_t offset); dup和dup2函数 复制代码 代码如下:#include <unistd.h> int dup(int oldfd); int dup2(int oldfd, int newfd); 上面两个函数都可用来复制一个现存的文件描述符。 由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。用dup2则可以用newfd参数指定新描述符的数值。如果newfd已经打开,则先将其关闭。如果newfd等于oldfd,则dup2返回newfd而不关闭它。 图3.3显示了这种情况。 假定我们的进程执行了: newfd = dup(1); 当此函数执行时,假设下一个可用的描述符是3。因为这两个描述符指向同一个文件表项,所以他们共享文件标志以及同一文件偏移量。 sync、fsync和fdatasync 复制代码 代码如下:#include <unistd.h> void sync(void); int fsync(int fd); int fdatasync(int fd); 当将数据写入文件时,内核通常将数据复制到一个缓冲区,直到缓冲区写满,再将缓冲区排路输出队列,然后等待其到达队首,才进行实际的I/O操作。这种输出防暑被称为延迟写。延迟写减少了磁盘的读写次数,但却降低了文件内容的跟新速度。当系统发生故障时,延迟写可能造成文件跟新内容的丢失。为了保证磁盘上实际文件系统与缓冲区高速缓存中内容一致性,UNIX系统提供了sync、fsync和fdatasync 三个函数。 fcntl函数 复制代码 代码如下:#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); 可以改变已经打开文件的性质。 复制一个现有的描述符(cmd=F_DUPFD) 可以用fcntl函数设置文件状态,常用设置套接字描述符为非阻塞O_NONBLOCK ioctl函数 提供了一个用于控制设备及其描述符行为和配置底层服务的接口。 /dev/fd |
请发表评论