文件I/O

Linux顶层目录结构:

 /              根目录
├── bin     存放用户二进制文件
├── boot    存放内核引导配置文件
├── dev     存放设备文件
├── etc     存放系统配置文件
├── home    用户主目录
├── lib     动态共享库
├── lost+found 文件系统恢复时的恢复文件
├── media   可卸载存储介质挂载点
├── mnt     文件系统临时挂载点
├── opt     附加的应用程序包
├── proc    系统内存的映射目录,提供内核与进程信息
├── root    root 用户主目录
├── sbin    存放系统二进制文件
├── srv     存放服务相关数据
├── sys     sys 虚拟文件系统挂载点
├── tmp     存放临时文件
├── usr     存放用户应用程序
└── var     存放邮件、系统日志等变化文件

 

文件操作一般用到5个函数:

open、read、write、lseek、close

对于内核而言,所有打开的文件都通过文件描述符(非负整数)引用。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。

当读写一个文件时,用open或creat返回一个文件描述符标识该文件,将其所为参数传给read或write。

UNIX系统shell使用文件描述符0、1、2分别与进程的标准输入、标准输出、标准错误输出相关联。

在依从POSIX的应用程序中,幻数0、1、2应替换成符号常量STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,定义在头文件<unistd.h>中。

/dev/fd/的目录其目录项是名为0,1,2等文件,打开文件/dev/fd/n相当于复制描述符n。

fd = open("/dev/fd/0", mode)等效于fd = dup(0) 

 

open函数

oflag常量包含:O_RDONLY、O_WRONLY、O_RDWR、O_APPEND、O_CREAT等。

 

lseek函数

设置当前文件偏移量。

whence值为:

SEEK_SET  以文件开头为锁定的起始位置。0
SEEK_CUR 以目前文件读写位置为锁定的起始位置。1
SEEK_END 以文件结尾为锁定的起始位置。2

 

read函数

因为read和write都在内核执行,所以称这些函数为不带缓冲的I/O函数。

 

每个打开的文件(或设备)都有一个v节点(v-node)结构。v节点包含了文件类型和对此文件进行操作的函数的指针。v节点包含了该文件的i节点(i-node索引节点)。

打开文件的内核数据结构                        两个独立进程各自打开同一个文件

在完成每个write后,在文件表项中的当前文件偏移量即增加所写的字节数。

dup函数或fork后,父、子进程对于每一个打开文件描述符共享同一个文件表项。

 

原子操作用pread和pwrite

调用pread相当于顺序调用lseek和read,过程中无法终端其定位和读操作,不更新文件指针。

 

复制一个现存的文件描述符 

sync、fsync和fdatasync函数

"r"(只读) 
 为输入打开一个文本文件,不存在则失败
 
"w"(只写)
 为输出打开一个文本文件,不存在则新建,存在则删除后再新建
 
 "a"(追加)
 向文本文件尾部增加数据,不存在则创建,存在则追加
 
'rb"(只读) 
 为输入打开一个二进制文件,不存在则失败
 
"wb"(只写) 
 为输入打开一个二进制文件,不存在则新建,存在则删除后新建
 
"ab"(追加) 
 向二进制文件尾部增加数据,不存在则创建,存在则追加
 
"r+"(读写) 
 为读写打开一个文本文件,不存在则失败
 
"w+" (读写)
 为读写建立一个新的文本文件,不存在则新建,存在则删除后新建
 
 "a+"(读写)
 为读写打开一个文本文件,不存在则创建,存在则追加
 
"rb+"(读写)
 为读写打开一个二进制文件,不存在则失败
 
"wb+"(读写)
 为读写建立一个新的二进制文件,不存在则新建,存在则删除后新建
 
 "ab+"(读写)
 为读写打开一个二进制文件,不存在则创建,存在则追加

 

      文件有文件名与数据,这在 Linux 上被分成两个部分:用户数据 (user data) 与元数据 (metadata)。用户数据,即文件数据块 (data block),数据块是记录文件真实内容的地方;而元数据则是文件的附加属性,如文件大小、创建时间、所有者等信息。在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名。文件名仅是为了方便人们的记忆和使用,系统或程序通过 inode 号寻找正确的文件数据块。在 Linux 系统中查看 inode 号可使用命令 stat 或 ls -i。

      Linux链接分为硬链接和符号链接(软链接)。默认ln命令产生硬链接。链接为 Linux 系统解决了文件的共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处。

      硬连接指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。

      另外一种连接称之为符号连接(Symbolic Link),也叫软连接。软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

 

      文件类型:

  (1)普通文件

  (2)目录文件

  (3)块特殊文件:提供对设备(如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。

  (4)字符特殊文件:提供对设备不带缓冲的访问,每次访问长度可变。系统所有设备是字符特殊文件或块特殊文件。

  (5)FIFO:用于进程间通信,又叫命名管道(named pipe)。

  (6)套接字socket:用于进程间的网络通信,也可用于在一台宿主机上进程之间的非网络通信。

  (7)符号链接:指向另一个文件

 

每次一个字符的I/O:

int getc(FILE *fp);    // 可被实现为宏

int fgetc(FILE *fp);

int getchar(void);    // 等价于getc(stdin)

若成功则返回下一个字符(unsigned char转换为int);到达结尾或出错返回EOF(负值,一般为-1)。

int putc(int c, FILE *fp);

int fputc(int c, FILE *fp);

int putchar(int c);

 

每次一行I/O:

char *fgets(char *buf, int n, FILE *fp);

char *gets(char *buf);    // 容易造成缓冲区溢出;不将换行符存入缓冲区,会删除

若成功则返回buf;到达文件结尾或出错返回NULL。

int fputs(const char *str, FILE *fp);  // null符终止字符串

int puts(const char *str);

若成功则返回非负值,出错返回EOF

 

二进制I/O:

size_t fread(void *buffer, size_t size, size_t count, FILE *stream);  // 从文件流中读数据,最多读count个元素,每个元素size字节

size_t fwrite(const void *buffer, size_t size, size_t count, FILE *stream);  // 向文件写入一个数据块,最多写count个元素,每个元素size字节

若成功返回实际读写的数据项个数,否则返回0。

 

定位流:

long ftell(FILE *fp);    // 成功返回当前文件位置指示;出错返回-1L

int fseek(FILE *fp, long offset, int whence);    // 成功返回0,出错返回非0值。 whence:SEEK_SET,SEEK_CUR,SEEK_END

void rewind(FILE *fp);

 

格式化I/O:

int printf(const char *format,...);

int fprintf(FILE *stream, const char *format, [argument]);    // 两个函数返回值,成功返回输出字符数;出错返回负值

int sprintf(char *buffer, const char*format, [argument]...);

int snprintf(char *buffer, size_t size, const char*format,);    // 两个函数返回值,成功返回存如数组的字符数;出错返回负值

 

posted @ 2015-11-06 10:31  LarryKnight  阅读(191)  评论(0编辑  收藏  举报