zoukankan      html  css  js  c++  java
  • Linux中无缓冲文件I/O API

    1.什么是无缓冲I/O
     我们首先要知道Linux操作系统提供给我们的用户程序调用的接口,除了使用库函数,还可以直接使用系统调用。而今天我要介绍的相关函数就是直接调用了内核的系统调用,所以说它是无缓冲的,它跟标准的I/O函数相对应。

    2.打开或者创建文件的函数:open()
     
    要操作相关文件,就必须获得该文件的句柄,专业点叫文件描述符。它是进程在打开一个文件或者创建一个文件时,内核返回给该进程的一个唯一的非负的整数,且一定是当前可以的描述符中最小的一个数。进程获得这个文件描述符后,就可以根据它来告诉read()或者write相关函数具体来操作哪个文件了。

        Tips:通常系统对一个进程可打开的文件描述符数量有一个默认值,可以使用命令ulimit -f查看,也可以使用ulimit命令重新设置该值。

     通常,系统有3个已经默认的文件描述符,即0代表标准输入,1表示标准输出,2表示标准错误,在unistd.h头文件中,把他们定义为常量,分别是STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO。

       open()函数为我们提供了该文件描述符:

    #include<fcntl.h>
    int open( const char * pathname,int flags, mode_t mode);

    pathname:即是我们要打开或者创建文件的名字,可以是相对路径,也可以是绝对路径。

    flags:重点介绍一下,它的取值比较多,在<fcntl.h>头文件中定义了很多常量:

      O_RDONLY:即以只读的方式打开该文件。
      O_WRONLY:即以只写的方式打开该文件。
      O_RDWR:即以读、写的方式打开该文件。
    以上这三个常量,flags必选选择其一,且只能选择其一。还有几个可选常量可以跟这三个之一组合使用,以达到不同的效果:
      O_CREAT:若欲打开的文件不存在则自动建立该文件.
      O_TRUNC :若文件存在并且以可写的方式打开时,此旗标会令文件长度清为0,而原来存于该文件的资料也会消失。
      O_APPEND :当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。

      O_EXCL 如果O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。

    比如,我们可以使用open("./filename" ,O_WRONLY|O_CREAT,mode),以写方式打开filename,如果filenam不存在则创建它。
    再如,open("./filename" ,O_WRONLY|TRUNC),就会将原来filename中的内容清除掉,从新写入新的值。
    还如,open(
    "./filename" ,O_WRONLY|O_CREAT|O_EXCL),可以测试filename是否存在,存在则报错,不存在则创建filename.
    当然flags还有几个其他的常量取值,就不一一介绍了,可以自己去查手册

      mode:仅当创建一个新文件需要指定该参数,该参数的意思是说文件以一个什么样的权限创建。

      open()调用成功后将返回文件描述符,出错则返回-1。

    系统还提供一个专门用来创建文件的函数create():

    #include<fcntl.h>
    int creat(const char * pathname, mode_tmode);

    其相当于open("pathname",O_WRONLY|O_CREAT|O_TRUNC,mode)。该函数有个不好之处是,只能以写的方式打开文件。有了open(),我们可以这样定义:

    open("pathname",O_RDWR|O_CREAT|O_TRUNC,mode)

    3.读函数read(),写函数write()

    #include<unistd.h>
    ssize_t read(
    int fd,void * buf ,size_t count);
    read()函数从fd中将指定大小count的字节读入buf中(注意,也可能读少于count的字节数,如到达了文件尾部,或者是特殊的文件)。成功返回读到的字节数,遇到结尾则返回0,失败返回-1。
    #include <unistd.h>
    ssize_t write (
    int fd,const void * buf,size_t count);

    write函数向fd中当前偏移量后面写入count大小字节的buf内容。如果成功返回写入的字节数大小,如果失败则返回-1.

    4.设置文件偏移量的函数lseek()

     每个打开的文件都有一个“当前文件偏移量”,在read(),write()的时候就可以根据该位置开始读写。使用lseek()则改变该位置。

    #include<unistd.h>
    off_t lseek(
    int fildes,off_t offset ,int whence);

    offset即指要相对whence便宜多少字节。whence不同的值使offset的意思不一样:

    SEEK_CUR:将偏移量设置为当前偏移量加offset个字节。
    SEEK_SET:将偏移量设置为文件起始处偏移offset个字节。
    SEEK_END:将偏移量设置为文件末尾加offset个字节。

    有个小技巧,如果要获得该文件当前文件偏移量,怎么办呢?可以这样:currPos = lseek(fd,0,SEEK_CUR);

    注意:当前文件偏移量不一定是非负的值,也可能是负值。所以判断lseek是否失败一定要测试其结果是否为-1,而不是小于0

    如果设置偏移量大于文件长度时,文件中将形成“空洞”,这种“空洞”并不占有磁盘的空间,它读取出来表现是0。

    5.一个copy程序

     

    #include <stdlib.h>
    #include
    <stdio.h>
    #include
    <fcntl.h>
    #include
    <unistd.h>

    #define BUFFER 4096

    int main(int argc,char *argv[])
    {
    int n;
    char buf[BUFFER];
    int fd1 = open(argv[1],O_RDONLY);
    int fd2 = open(argv[2],O_WRONLY);
    while( (n=read(fd1,buf,BUFFER))>0 )
    {
    if( (write(fd2,buf,n))!=n )
    {
    printf(
    "error\n");
    exit(
    1);
    }
    }
    close(fd1);
    close(fd2);
    exit(
    0);
    }

  • 相关阅读:
    android通过Canvas和Paint截取无锯齿圆形图片
    【转】mysql的cardinality异常,导致索引不可用
    mysql索引无效且sending data耗时巨大原因分析
    linux shell脚本通过参数名传递参数值
    git日志输出格式及两个版本之间差异列表
    jenkins结合ansible用shell实现自动化部署和回滚
    Linux下cp -rf总是提示覆盖的解决办法
    jenkins集成ansible注意事项Failed to connect to the host via ssh.
    ansible操作远程服务器报Error: ansible requires the stdlib json or simplejson module, neither was found!
    利用ssh-copy-id无需密码登录远程服务器
  • 原文地址:https://www.cnblogs.com/codebean/p/2079094.html
Copyright © 2011-2022 走看看