unix文件和i/o流

  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分别指向不同的文件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343