zoukankan      html  css  js  c++  java
  • Unix文件操作

    一、概述

    Unix文件操作常用函数包括openclosecreatlseekdupdup2fcntl等,

    其中open、creat、 fcntl函数需要包含头文件<fcntl.h>,

    其余几个函数需要包含头文件<unistd.h>。

    由于在Linux操作系统 中使用man命令可以非常方便的查找函数原型及示例,这里就不帖出函数原型了,只讲一下使用时需要注意的地方。

    二、文件描述符

    每一个在程序中打开的文件都有一个相应的文件描述符(file descriptor),Unix操作系统中的文件描述符保存在/dev/fd目录下。

    每一个进程对该目录读取到的结果都不想同(视该进程正在使用的文件 数而定)。

    如果由open函数直接读取该路径下的文件,将视为在此进程中对该文件描述符所对应的文件进行dup操作,在大多数操作系统中将忽略打开方式, 而部分操作系统要求打开方式为所涉及文件原先打开方式的子集。

    三、Flags

    当使用O_APPEND方式打开文件时,每次调用write函数会在文件最后面写入新数据,调用write函数后读取当前文件偏移量 (current offset)可以很清楚的看到该值与文件最大偏移量相等。

    如果使用了O_RDWR | O_APPEND方式打开文件,程序可以对该文件在任意位置实现读取操作(read),但写入操作(write)会使文件偏移量被重置,如果读取与写入混 合使用,可能会导致读取位置出现偏差。

    四、函数细说

    4. 1 creat & open  

      creat函数与

    open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);

      等同,使用creat函数的缺陷在于如果需要在创建的同时读写该文件,需要在创建后将文件关闭,重新以读写方式open该文件,相对而言,下面的调用方式更为简单:

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

      其中,O_TRUNC表示:如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0(即会清空文件内容)

    4.2 lseek

      在lseek函数中,偏移量(offset)是一个长整型,可正可负。如果偏移量大于文件最大偏移量,对该位置进行写入操作,将对文件进行扩展,文件中的空洞(从原文件最大偏移量到写入位置)被填充为0,但并不占用磁盘块

      例如:

    fd = creat("file.txt", S_IRWXU);
    lseek(fd,102400,SEEK_SET);
    write(fd,"abcdefg",7);

      程序执行后,使用"ls -ls file.txt"命令可以看出,文件file.txt所占块数为8.

     4.3 read

      使用read函数时,遇到以下情况会使read函数提前返回:

    • 文件读取遇到EOF。
    • 从终端中读取到一行内容。(STDIN_FILENO)
    • 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
    • 从管道或FIFO中读取到全部内容。
    • 某些面向记录的设备,例如磁带,一次最多返回一个记录。
    • 接收到中断信号。

    五、File Sharing

    5.1 说明

      在进程中,一个进程所打开的所有文件描述符存放在一个table中,table中的每条记录包括文件描述符falgs(file descriptor flags)和指向文件表的指针(fils pointer)。

      一个文件表包含一个文件的状态标志(file status flags),当前偏移量(offset),一个指向v-node表的指针。一个v-node表包括v-node信息,i-node信息,文件大小等。如 图1所示:

    图1. Unix文件表(进程中)

      在多个进程中,可能出现多个文件描述符指向同一个文件,此时如图2所示:

    图2. 多个进程中同时打开同一个文件

      当使用dup、dup2函数后,文件描述符将被复制,此时如图3所示:

    图3. dup后多个文件描述符指向同一个file table

    5.2 控制多进程对文件的访问

      在进行多进程或多线程编程时,由于无法控制CPU对进程和线程的调度,如果不加以控制,可能会在任意两条程序控制语句中间出现中断,导致数据被污染。

      可以使用原语来保证在特定操作中数据不会被污染,使数据同步。

      原语形式的文件读写函数为 pread和pwrite。

      也正因为数据可能被污染的原因,虽然dup2(file1,file2)与close(file2); fcntl(file1, F_DUPFD, file2)等价,但第一个函数不会导致数据被污染,我们应该使用第一个函数。

     

    5.3 文件更新

      在操作系统中,向文件中写入数据往往只是暂时写入至操作系统缓存中,由操作系统控制磁盘中文 件的更新时间。使用sync、fsync、fdatasync函数可以实现磁盘中文件的实时更新。

      使用sync函数时,文件表中的所有文件将被更新。

      fsync函数只更新制定文件。

      fdatasync函数只更新指定文件中的数据内容,而不更新相应的文件属性。

     

      如果file status flags中O_SYNC标志被设置,程序中每次对该文件的write操作都将导致文件被更新;如果O_DSYNC被设置,程序中每次对该文件的write操作都将导致文件中的数据部分被更新。

     5.4 fcntl

      fcntl函数可以修改已打开文件的属性。

      当使用fcntl函数获取文件状态标记(file status flags)时,由于O_RDONLY、O_WRONLY、O_RDWR标记具有排外型,无法被直接识别,需要由O_ACCMODE掩码转换后才可以被识 别。

      示例代码如下:

    #include <fcntl.h>
    int
    main(int argc, char *argv[])
    {
    int val;
    if (argc != 2)
        err_quit("usage: a.out <descriptor#>");
    if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
        err_sys("fcntl error for fd %d", atoi(argv[1]));
    switch (val & O_ACCMODE) {
        case O_RDONLY:
        printf("read only");
        break;
    case O_WRONLY:
        printf("write only");
        break;
    case O_RDWR:
        printf("read write");
        break;
    default:
        err_dump("unknown access mode");
    }
    if (val & O_APPEND)
        printf(", append");
    if (val & O_NONBLOCK)
        printf(", nonblocking");
    #if defined(O_SYNC)
    if (val & O_SYNC)
        printf(", synchronous writes");
    #endif
    #if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC)
    if (val & O_FSYNC)
    printf(", synchronous writes");
    #endif
    putchar('
    ');
    exit(0);
    }
  • 相关阅读:
    理解Objective-C Runtime (六)super
    理解Objective-C Runtime (五)协议与分类
    理解Objective-C Runtime(四)Method Swizzling
    理解Objective-C Runtime(三)消息转发机制
    Objective-C Runtime(二)消息传递机制
    matlab数学实验--第一章
    Python之json模块
    Python之os模块和sys模块
    Python之小练习
    vuedevtools 离线安装
  • 原文地址:https://www.cnblogs.com/wiessharling/p/4076336.html
Copyright © 2011-2022 走看看