前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux文件I/O函数

Linux文件I/O函数

作者头像
zy010101
发布2019-07-02 11:46:55
1.6K0
发布2019-07-02 11:46:55
举报
文章被收录于专栏:程序员

版权声明:本文为博主原创文章,转载请注明博客地址: https://cloud.tencent.com/developer/article/1454420

Linux文件描述符

在Linux下当一个进程打开文件的时候,OS会返回相应的文件描述符,程序为了处理该文件必须使用这个文件描述符。文件描述符是一个正整数。一般而言,当一个进程启动的时候,他会打开3个文件:标准输入,标准输出,标准错误。这3个文件对应的文件描述符分别是0,1,2.通常使用宏:STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO.文件描述符是一个索引,指向内核中打开文件的记录表。

Linux操作系统给我们提供了6个系统调用create,open,write,close,read,lseek。系统调用是不带缓冲区的。他们是POSIX标准提供的。这些函数需要的头文件#include<fcntl.h>,#include<sys/types.h>,#include<sys/stat.h>。可以使用man命令来查看这些函数的用法以及所需要的头文件。首先,使用man man命令可以知道,系统调用在第二章。

使用命令man 2+函数名字就可以看到系统调用的详细描述。

open函数和creat函数

参数pathname是路径;flags非常多,可以从手册中看到,常用的就是 O_RDONLY, O_WRONLY, O_RDWR等。mode标示了对文件的访问权限,如下所述。

mode值包含了对文件的访问权限位。正如上面描述的一样,每个文件有9个访问权限位,并且可以分为3组。

mode

含义

S_IRUSR

用户读

S_IWUSR

用户写

S_IXUSR

用户执行

S_IRGRP

组读

S_IWGRP

组写

S_IXGRP

组执行

S_IROTH

其他读

S_IWOTH

其他写

S_IXOTH

其他执行

如果打开的文件是在某个目录文件下,那么该目录必须是可执行的,因为对于目录文件而言,可执行代表着搜索位,我们可以找该目录下的文件。目录的读只代表我们可以读取该目录的文件列表,不能进行其他操作。如果当前打开了一个文件,如果是root用户的进程,那么它肯定能访问该文件。如果进程是文件所有者执行的,那么对文件的权限取决于第一组的权限;如果进程是文件所有者所在组或者附属组之一,那么对文件的权限取决于第二组权限。若进程是其他用户执行的,那么对文件的操作取决于第三组权限。

在使用open函数打开一个文件的时候,最常用的三个参数是:O_WRONLY(只写),O_RDONLY(只读),O_WRRD(可读可写)另外两种是:O_EXEC(执行),O_SEARCH(搜索,应用于目录)。另外open打开的文件,返回的文件描述符一定是最小的未使用描述符。path所指定的路径可以是绝对路径,也可以是相对路径。

flags中有些参数可以帮助我们创建文件

creat函数的不足之处是它创建的文件以只写的方式打开。当我们拥有上述参数的时候,就可以使用open函数来代替creat函数创建文件。即:

代码语言:javascript
复制
open(path,O_RDWR|O_CREAT|O_TRUNC,mode)

open函数成功时,返回一个文件描述符;若出错,返回 -1。

如果返回了-1,表示出错,我们还可以由perror函数知道出现的错误具体是什么。

当Linux系统函数出错的时候,一般会返回一个负值给errno。POSIX和ISO C将errno定义为一个符号。它可以是一个包含出错编号的整数,也可以是一个返回出错编号指针的函数,具体由开发者去实现。C定义了perror函数来打印出错信息。

perror函数首先输出参数s的内容,然后是一个冒号,一个空格,接着输出errno所对应的出错消息。然后换行。

read函数

fd是文件描述符;buf是缓冲区,用于保存从文件中读取的内容。count是读取的字节数。如果read成功,返回读取到的字节数。若已到达文件尾端,返回0。读取出错返回-1。

write函数

如果写入成功,返回以写字节数,否则,返回-1。参数的意义和read函数一致。

close函数

关闭一个文件并释放该进程加在该文件上的所有锁。当一个进程终止的时候,会自动关闭它打开的所有文件。所以有时候并不显式的使用close关闭文件。close函数返回0表示成功,返回-1表示错误。

lseek函数

每个打开文件都有一个与其相关联的“当前文件偏移量”。用于计算从文件开始处的字节数。通常,读写都是从当前文件偏移量处开始的,并使用偏移量增加所读写的字节数。系统默认该偏移量为0。可以使用lseek函数来指定一个打开文件的偏移量。

参数whence表示从哪儿开始。它有3个值,如下。

offset的值的意义具体就根据whence参数的值来决定。

一个简单的例子如下:

代码语言:javascript
复制
#include <sys/types.h>
#include <sys/stat.h>    
#include <fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>

int main()
{
    int fd;
    char str[20] = {"Hello World!"};
    char buf[20] = {0};     //初始化为0,为了方便打印。
    int flag;
    //在当前路径下打开一个new.txt文件,若不存在就创建它;若存在则以可读可写方式打开,并且从长度0截断
    fd = open("./new.txt",O_CREAT|O_TRUNC|O_RDWR,0777);
    if (-1 == fd)        
    {
        perror("open fail");     //包含在stdio中的函数。
        exit(1);
    }
    
    flag = write(fd,str,20);    //给文件写入内容
    if(-1 == flag)
    {
        perror("write fail");
        exit(1);
    }

    lseek(fd,0,SEEK_SET);       //使用lseek将文件偏移量设置为文件开始处
    //如果没有这一步,那么下面的read无法读取到文件内容,因为文件偏移量已经到了字符串结束符处。

    flag = read(fd,buf,20);     //读取文件内容
    if(-1 == flag)
    {
        perror("read fail");
        exit(1);
    }

    flag = close(fd);       //关闭文件
    if(-1 == flag)
    {
        perror("close fail");
        exit(1);
    }

    printf("%s\n",buf);       //打印缓冲区中的内容。
    return 0;
}

打印结果如下:

需要注意的是,buf数组需要全部初始化为0,'\0'的ASCII就是0.这样将打开的文件中读取的文本信息打印的时候才能正常打印,不会乱码。否则不知道在哪儿终止,将会产生乱码。

注意:在使用Linux的系统调用操作文件的时候,是无缓冲的,这点很重要。当你在做少量,大批次写入的时候效率会很低。因此注意使用缓冲(用数组的之类的暂时保存一下),能提高I/O效率。

lseek不可以用于管道,FIFO,socket文件。另外lseek的文件偏移量的大小可以大于当前文件的长度,在这种情形下,对该文件的下一次写将加长该文件,并在文件中构成一个空洞。文件空洞并不要求在磁盘上占据空间。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年06月07日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档