unix文件和i/o流

1. 关于unix文件结构

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

#include 

   

    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

 

 

2. 关于unix文件i/o流

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

#include 

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 

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 

int
fclose(FILE *stream);

void
fcloseall(void);

c. 读写流

读写流也分几种方法:

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

#include 

int
fgetc(FILE *stream);

int
getc(FILE *stream);

int
getc_unlocked(FILE *stream);

int
getchar(void);

int
getchar_unlocked(void);

int
getw(FILE *stream);



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 

char *
fgets(char * restrict str, int size, FILE * restrict stream);

char *
gets(char *str);

int
fputs(const char *restrict s, FILE *restrict stream);

int
puts(const char *s);

 

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

#include 



size_t

fread(void *restrict ptr, size_t size, size_t nitems,

FILE *restrict stream);



size_t

fwrite(const void *restrict ptr, size_t size, size_t nitems,

FILE *restrict stream);

 

与文件描述符0,1,2分别指标准输入,标准输出,标准错误文件相对,流也有stdin,stdout,stderr

 

3. 进程与文件

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

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

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

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

 

 

 

 

 

 

你可能感兴趣的:(Linux/Unix编程)