美文网首页
unix文件和i/o流

unix文件和i/o流

作者: 文蜘蛛 | 来源:发表于2019-12-07 21:44 被阅读0次
    1. 关于unix文件结构

    在unix/linux文件系统中,一切皆是文件,目录是文件,设备是文件,文件是文件......文件需要有文件的各项属性,在unix中,可以使用stat函数族来获取文件属性。使用stat函数获取的节点文件存储在struct stat *buf指向的内存中。

    #include <sys/stat.h>
     
        int
        fstat(int fildes, struct stat *buf);
     
        int
        lstat(const char *restrict path, struct stat *restrict buf);
     
        int
        stat(const char *restrict path, struct stat *restrict buf);
     
        int
        fstatat(int fd, const char *path, struct stat *buf, int flag);
     
    
        struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is NOT defined */
     
            dev_t    st_dev;    /* device inode resides on */
     
            ino_t    st_ino;    /* inode's number */
     
            mode_t   st_mode;   /* inode protection mode */
     
            nlink_t  st_nlink;  /* number of hard links to the file */
     
            uid_t    st_uid;    /* user-id of owner */
     
            gid_t    st_gid;    /* group-id of owner */
     
            dev_t    st_rdev;   /* device type, for special file inode */
     
            struct timespec st_atimespec;  /* time of last access */
     
            struct timespec st_mtimespec;  /* time of last data modification */
     
            struct timespec st_ctimespec;  /* time of last file status change */
     
            off_t    st_size;   /* file size, in bytes */
     
            quad_t   st_blocks; /* blocks allocated for file */
     
            u_long   st_blksize;/* optimal file sys I/O ops blocksize */
     
            u_long   st_flags;  /* user defined flags for file */
     
            u_long   st_gen;    /* file generation number */
     
        };
    

    这里需要简单介绍以下几个struct stat元素和相关函数,实际使用时可以使用man查看具体使用方法,为了节约时间和保持思维连贯性,在此不做赘述。

    a. st_mode

    表示文件类型和访问权限

    umask 设置创建文件时默认的permission

    chmod

    fchmod

    chown

    fchown

    lchown

    b. st_ino

    st_ino表示一个inode节点号,在unix/linux系统中,我们为每一个文件分配一个inode指针,这个inode指针指向文件存储的一组内存块blocks,如果一个block是4k,而我们文件中存了7k的文件,那么操作系统就会给这个文件分配2个block和一个inode,inode就是这两个block的索引。

    c. st_nlink

    关于链接计数需要具体分文件和目录来讨论。对于文件来说,st_nlink表示指向该文件inode的目录项数,也可以称之为硬链接数(hard link),这意味着什么呢?假设我在/usr/bin/目录下有一个文件f_nlink,f_nlink的inode号是1553,这个时候/usr/bin目录项中必然有一条目录项是(1553,f_nlink),此时f_nlink的st_nlink就是1;如果使用ln命令给f_nlink创建一个硬链接到/usr/目录下,则在/usr/目录中也必然有一条目录项是(1553,f_link),/usr/和/usr/bin/都有目录想指向1553这个inode,此时f_nlink的st_nlink是2(硬链接数是2);此时如果在/usr/bin/目录下删除f_nlink(使用unlink或者rm),则f_nlink的链接数减少1,但是inode仍然存在,且从/usr/目录下也可以访问f_nlink文件,只有当链接数减为0时才会删除f_nlink的inode,彻底删除文件释放内存。这里又需要扩展开来聊聊软链接了,对于软连接来说,如果本体被删除,则副本就不能访问本体。

    对于目录来说,一个目录项下有几个文件或者子目录,则链接数就是几(包括.和..)。

    硬链接有两个限制:(1)不允许给目录创建硬链接,防止产生环路,遍历目录时陷入死循环;(2)只有在同一个文件系统中的文件之间才能创建硬链接,这也很好理解,只有在同一个文件系统中才能访问inode

    1. 关于unix文件i/o流

    在unix系统调用层面我们使用read和write来读写文件。

    #include <unistd.h>
     
    ssize_t read(int fd, void *buf, size_t nbytes);
    参数:
    fd: 将要读取的数据的文件描述符
    buf: 所要读到数据的内存缓冲的缓冲区指针
    nbytes: 读取的数据大小
    返回值:
    返回读取的数据大小,如果读到文件末尾则返回0;读取失败返回-1。
     
    ssize_t write(int fd, const void *buf, size_t nbytes);
    返回值:
    写入文件成功则返回写的字节数;失败返回-1。
    

    当频繁的使用read和write系统调用读写文件,进程就需要不断的在内核态和用户态之间转换,系统开销太大;因此流(stream)就出现了,流的结构FILE了几个部分:文件描述符fd,指向该流缓冲区指针,缓冲区大小,当前缓冲区中的字符数,出错标志等。我们通常使用文件指针FILE来表示流,个人认为FILE的使用是对文件系统调用函数的又一层封装。总结几个有关流的unix函数如下:

    a. 打开流

    #include <stdio.h>
     
    FILE *
    fdopen(int fildes, const char *mode);
     
    FILE *
    fopen(const char *restrict filename, const char *restrict mode);
     
    FILE *
    freopen(const char *restrict filename, const char *restrict mode,
    FILE *restrict stream);
    

    b. 关闭流

    #include <stdio.h>
     
    int
    fclose(FILE *stream);
     
    void
    fcloseall(void);
    

    c. 读写流

    读写流也分几种方法:

    无缓冲,即每次只读或者写一个字符的i/o流。

    #include <stdio.h>
     
    int
    fgetc(FILE *stream);
     
    int
    getc(FILE *stream);
     
    int
    getc_unlocked(FILE *stream);
     
    int
    getchar(void);
     
    int
    getchar_unlocked(void);
     
    int
    getw(FILE *stream);
    
    #include <stdio.h>
     
    int
    fputc(int c, FILE *stream);
     
    int
    putc(int c, FILE *stream);
     
    int
    putc_unlocked(int c, FILE *stream);
     
    int
    putchar(int c);
     
    int
    putchar_unlocked(int c);
     
    int
    putw(int w, FILE *stream);
    

    行缓冲,即每次读或者写一行字符的i/o流,每行以一个换行符\r终止。

    #include <stdio.h>
     
    char *
    fgets(char * restrict str, int size, FILE * restrict stream);
     
    char *
    gets(char *str);
    
    #include <stdio.h>
     
    int
    fputs(const char *restrict s, FILE *restrict stream);
     
    int
    puts(const char *s);
    

    全缓冲,也称直接i/o,每次i/o操作读或者写某个数量的对象。

    #include <stdio.h>
     
    size_t
    fread(void *restrict ptr, size_t size, size_t nitems,
    FILE *restrict stream);
    
    1. 进程与文件

    在一个进程中打开文件,则进程表项中有一个分配一个对应的文件描述符fd和其指针映射;指针指向一个文件表,每当打开一个文件就会分配一个文件表,文件表中存储了文件状态标志(只读,只写,可读可写),当前文件偏移量,v节点指针;v节点指针指向v节点信息,v节点又包含了inode。

    a. 使用dup/dup2可以复制fd或者改变fd,这样可以创造进程表中两个fd指向同一个打开文件的情况;

    b. 可以打开一个文件两次,则有两个进程表项中分别有fd指向文件表,每个文件表都有其自己的文件偏移量,涉及到同步问题;

    c. 一个进程表中,两个fd分别指向不同的文件。

    相关文章

      网友评论

          本文标题:unix文件和i/o流

          本文链接:https://www.haomeiwen.com/subject/ujhpgctx.html