linux 文件io常用操作总结

对文件的操作,究根结底也就是那么几种行为,分别为打开,读,写,关闭。

一、文件描述符:至于什么是文件描述符,这个是很简单的概念。
二、打开文件
open(path,flag,...)
1、创建新文件
open(path,O_CREAT,filemode)
当创建一个新文件的时候,可以使用 O_CREAT 和 O_EXCL 组合,这样可以保证新文件一定是由当前进程创建。
2、O_APPEND标识
这是一个 文件状态标识 ,对该文件的所有写操作之前都会讲文件指针移动到文件的末尾,这样就相当于追加写。这是一个原子操作。
三、读文件
read(fd,buf,len):从fd代表的文件读取 len 长度的字节内容,内容保存到 buf 缓冲区中。
四、写文件
write(fd,buf,len):将buf缓冲区中的内容写到fd指向的文件,长度为len
五、关闭文件
close(fd);
进程结束之后,OS会自动关闭所有打开的文件描述符,但是最好自己主动关闭,因为文件描述符是一种资源,如果打开的数量太多,可能造成后续的open操作失败。
六、设置文件的偏移量
lseek(fd,offset,whence)
如果执行成功则返回此时的文件偏移量,如果失败,则返回 -1,所以可以利用这个函数来判断一个文件是否可以设置偏移量。例如管道就不可以设置偏移量。
七、原子定位并读写
pread(fd,buf,nbytes,offset)
pwrite(fd,buf,nbytes,offset)
  • offset:表示从哪个位置开始读取或者写入数据。偏移量是从文件开头开始计算
pread和pwrite函数是linux提供的另一种读写文件的函数,pread()相当于顺序调用了 lseek() 和 read() 函数。pwrite也类似。但是这个过程是原子的,即调用 lseek()和 read/write 的过程是原子的。
八、文件描述符操作
dup(fd)
dup2(fd,fd2)
这两个函数可以复制一个文件描述符,但是返回的新的文件描述符中的 O_CLOEXEC标识都会被清除。
fcntl()这个函数可以对文件描述符的一些属性进行设置。因为有的时候我们只能拿到文件描述符,所以只能通过这个函数对文件描述符进行设置或者获取一些文件的信息。比如管道,我们就只知道他们的文件描述符。
八、注意事项:
read和write之后文件的偏移量会跟着改变,但是pread和pwrite并不会改变文件的偏移量。

九、内核中关于文件的几个数据结构
1、内核为每个进程维护一个进程表项,这个数据结构是一个数组,保存了文件描述符的一些信息,比如文件描述符标识(O_CLOEXEC).
2、内核为每个打开的文件维护一个文件表项。这个数据结构中保存了当前文件的偏移量。同一个进程多次打开同一个文件,那么内核会为该文件维护多个文件表项,这样每个文件描述符都会有自己的当前文件偏移量。
3、v节点表。一个物理文件对应一个v节点。同一个文件只会有一个v节点。



打开文件的内核数据结构

十一、代码分析,结合上图:
1. 对同一个文件描述符的读和写位置共享。
测试代码:
char   buf[128];
int   main( int   argc, char   *argv[])
{
         char   *s =  "test" ;
         int   fd = open( "test.txt" ,O_RDWR);
         if (fd == -1)
         {
                 perror ( "open test.txt failure" );
                 exit (EXIT_FAILURE);
         }
 
         int   readNum = read(fd,buf,3);
         write(fd,s,4);
         if (-1 == close(fd))
         {
                 perror ( "close failure" );
                 exit (EXIT_FAILURE);
         }
         exit (EXIT_SUCCESS);
}

测试条件,test.txt文件的初始内容为 123456789
测试结果:程序执行之后test.txt文件的内容为 123test89
分析:
1. 对 test.txt 进行了读写打开
2. 先对test.txt 读3个字节,所以此时fd的偏移量应该是3
3. 接着对fd写4个字节,根据最终的输出结果可以知道此时是从偏移量为3的地方开始写的,所以对于同一个文件描述符来说,读写位置是共享的。

原因分析:因为文件的偏移量保存在文件表项中。read和write都是对同一个fd操作,所以他们共享了相同的文件偏移量。

2. 同一个进程多次打开同一个文件
测试代码:

int   main( int   argc, char   *argv[])
{
         char   buf[10];
         char   *s =  "test" ;
         int   fd1 = open( "test.txt" ,O_RDWR);
         int   readNum = read(fd1,buf,3);
         int   fd2 = open( "test.txt" ,O_RDWR);
         write(fd2,s,4);
}
测试条件,test.txt文件的初始内容为 123456789
测试结果:程序执行之后test.txt文件的内容为 test56789
分析:
1. 对 test.txt 进行了第一次open操作得到fd1
2. 先通过fd1对test.txt 读3个字节,所以此时fd1所对应的偏移量应该是3
3. 接着对test.txt进行了第二次open操作,得到了fd2,
4. 通过fd2对test.txxt写4个字节,根据最终的输出结果可以知道此时是从偏移量为0的地方开始写的
5. 综上所述,如果对同一个文件打开多次,那么这些文件描述符所对应的内核结构是独立的。
6、从上面的结果也可以看出来,即使是同一个文件,如果我们打开了多次,那么内核也会维护多个打开文件表项。这样可以让每个文件描述符可以拥有独立的文件偏移量等。


十六、打开的文件数量和文件描述符的关系
每打开一个文件都要为该文件分配一个文件描述符。但是我们还可以使用dup()等函数来复制相同的文件描述符,这样就会导致有些文件会对应多个文件描述符。可能还会有其他的原因,但是至少上面的原因是其中一个。这样就会造成二者不相同。
我们创建管道的时候使用pipe()调用时,一个管道文件会产生两个文件描述符。这个也会造成打开的文件数量和获得的文件描述符数量不一致。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值