文件IO
在unix世界中视一切为文件,无论最基本的文本文件还是网络设备或是u盘,在内核看来它们的本质都是一样的。大多数文件IO操作只需要用到5个函数:open 、 read 、 write 、 lseek 以及 close. 这些函数并不是 ISO C 的组成部分,而是unix的系统调用函数。相比较ISO C中带缓冲的IO操作函数,它们是不带缓冲的IO函数。它们之间的区别看上去是这样的:

可以简单的这么来理解,write函数直接将内容写到文件中。而像printf这样的函数将内容先写到缓冲区,然后由缓冲区的方式(行缓冲或者全缓冲)来决定什么时候将缓冲区的内容写到具体的文件中。下面对文件IO操作中的概念还有函数一一介绍。
文件IO的基本概念
下面的这张图表示了打开文件的内核数据结构:

简单来说,首先是一个文件面向用户的文件描述符,然后文件指针指向一个文件表,用来保存文件相关的信息。接下来可以认为与文件物理存储相关的结构。其中涉及的几个文件IO基本概念解释如下:
文件描述符
当调用open函数打开一个文件时会返回一个非负整数来标志该文件。一方面方便内核的管理,另一方面方便代码基于此标志进行后续的文件操作。在UNIX系统中,stdin与文件描述0相互关联;stdout与文件描述符1相互关联;stderr与文件描述符2相互关联。并使用下面的宏定义来提高程序的可读性:STDIN_FILENO 、 STDOUT_FILENO 、 STDERR_FILENO.
文件描述符标志
这个概念容易混淆,文件描述符标志即close-on-exec标志位。如果文件描述符设置了该标志,表示在通过fork函数产生的子进程中调用exec族函数时,该文件描述符会被自动关闭。这样做可以用来保护文件描述符资源,防止泄露。
文件状态标志
文件状态标识用来说明该文件的基本属性。比如是否可读、是否可写、是否阻塞等等。下一小节中会详细的描述。
文件偏移量
当执行读或者写操作时,第一个面临的问题就是在什么位置执行这些操作。文件偏移量这个标志就指明了当前文件相对于起始位置的偏移量。
open函数
open函数的原型如下:
#include <fcntl.h> int open(const char *path, int oflag, .../* mode_t mode */); 返回值:若成功返回文件描述符,若出错返回-1
此函数用 path 参数指定文件的路径,用 oflag 参数指定文件状态标识,说明如下:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR: 读写打开
以上三种属于互斥的关系,只能选其一。下面的这些标志位可以通过 '|' 操作来进行叠加。
O_APPEND: 每次写时都追加到文件的尾端。
O_CLOEXEC: 它的含义在上文 文件描述法标志位 中已经阐述清楚了。
O_CREAT: 若文件不存在则创建它。使用此选项时,open函数需同时说明第三个参数mode,来指定该文件的访问权限。如果文件已经存在并不会出错,而是重新创建新文件。
O_EXCL: 如果同时指定了OCREATE,且文件存在,则出错。这个标志可以用来测试文件是否存在,也可以保证对现有文件的保护。
O_NOCTTY: 如果path引用的是终端设备,则不将该设备分配作为此进程的控制终端
O_NOBLOCK: 如果path引用的是一个FITO、一个块特殊文件或一个字符特殊文件,则此选项为文件的本次打开操作和后续的IO操作设置非阻塞方式。
O_SYNC: 使每次write等待物理IO操作完成,包括由该write操作引起的文件属性更新所需的IO。
O_TRUNC: 如果文件存在,而且为只写或读-写成功打开,则将其长度截断为0。
常用的标志位为 O_APPEND, O_CLOEXEC, O_NOBLOCK, O_TRUNC。这些标志位可以通过使用 | 操作符来实现多个开启,如
open("./test.txt", O_RDWD | O_APPEND | O_NOBLOCK);
以读写、追加、非阻塞的方式打开当前目录下的test.txt文件。
此外,openat() 与 create() 函数也可以实现打开文件的功能。但一般使用 open 函数即可。
lseek函数
lseek用于设置当前文件偏移量,其原型如下:
#include <unistd.h> off_t lseek(int fd, off_t offset, int whence); 返回值:若成功返回文件的新的偏移量,若出错返回-1
这个函数将fd描述符的文件的偏移量设置到距离 whence 位置 offset 字节数的地方。whence 示意如下:
SEEK_SET: 文件开始处
SEEK_CUR: 文件当前位置
SEEK_END: 文件结尾
若 lseek 成功执行,返回新的文件偏移量。这是一个非常有用的函数。如果想知道文件当前的偏移量,可以使用下面的这个技巧。
off_t offset; offset = lseek(fd, , SEEK_CUR);
read write函数
读写函数放在一起比较,便于记忆。read 函数的原型如下:
#include <unistd.h> ssize_t read(int fd, void *buf, size_t nbytes); 返回值:若成功返回读到的字节数,若已到文件结尾返回0,若出错返回-1
fd为所读取文件的描述符,buf用于存放的缓冲区指针,nbytes为预计要读取的字节数。关于返回值:如果read执行成功,返回实际读到的数据(如已到文件尾端,返回0);如果read出错,返回-1。
有多种的情况下,read 函数多读取的字节数可能会小于所要求的字节数,在网络编程下尤其要注意这一点。
write的函数原型如下:
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t nbytes); 返回值:若成功则返回已写的字节数,若出错返回-1
buf指针指向缓存区,nbytes为预计要写的字节数,若 write 函数执行成功,返回实际写入的字节数;若出错,返回-1。其返回值通常与参数nbytes的值相同,否则表示出错。
文件IO操作举例
下面举一个文件处理的小例子,原来文件的结构如下:
[task]
1. test 1
2. test 2
[End]
写一个函数来实现向task和end之间插入一个新的项。下面是代码实现:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
void taskAdd(const char *str)
{
int fd;
;
int i;
char c;
off_t offset;
] = {};
] = {};
// copy data
strcpy(line, str);
int len = strlen(line);
line[len] = '\n';
line[len + ] = '\n';
// open the file
)
{
printf("open error\n");
return;
}
// read one line once a time
)) > && nRead < )
{
)) == '\n')
{
// find the [End] flag
)
{
, SEEK_CUR)) < )
{
printf("lseek error\n");
return;
}
) < )
{
printf("read error\n");
return;
}
, SEEK_SET)) < )
{
printf("lseek error\n");
return;
}
)
{
printf("write error\n");
return;
}
)
{
printf("write error\n");
return;
}
close(fd);
return;
}
memset(buf, , );
nRead = ;
}
}
}
文件IO的更多相关文章
- 标准io与文件io
A: 代码重复: 语句块1: while(判断) { 语句块2: 语句块1: } 上面可以改写为: while(1) { 语句块1: if(判断) break: 语句块2: } B: 标准IO和文件I ...
- 文件IO函数和标准IO库的区别
摘自 http://blog.chinaunix.net/uid-26565142-id-3051729.html 1,文件IO函数,在Unix中,有如下5个:open,read,write,lsee ...
- 转 漫谈linux文件IO
在Linux 开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO.本篇文件打算详细全面,深入浅出.剖析文件IO的细节.从多个角度探索如何提高IO性能.本文尽量用 ...
- (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- Java文件IO操作应该抛弃File拥抱Paths和Files
Java7中文件IO发生了很大的变化,专门引入了很多新的类: import java.nio.file.DirectoryStream;import java.nio.file.FileSystem; ...
- Java 文件IO续
文件IO续 File类 用来将文件和文件夹封装成对象 方便对文件和文件夹的属性信息进行操作 File对象可以作为参数传递给流的构造函数 Demo1 File的构造方法 public cla ...
- Java 文件IO
文件IO Java IO IO流用来处理设备之间的数据传输 Java对数据的操作是通过流的方式 Java用于操作流的对象都在IO包中 按操作数据分为 字节流和字符流 字符流的 ...
- 文件IO和标准IO
2015.2.26 星期四,阴天 今天的内容主要是文件IO man 手册的分册: man -f open 查看那些分册中有openman 1 -- 普通的命令程序man 2 -- 系统调用man 3 ...
- 文件IO操作
前言 本文介绍使用java进行简单的文件IO操作. 操作步骤 - 读文件 1. 定义一个Scanner对象 2. 调用该对象的input函数族进行文件读取 (参见下面代码) 3. 关闭输入流 说明:其 ...
随机推荐
- Javascript 正则表达式笔记
\d 元字符 + 量词 \w 常用的字符a-zA-Z0-9 .除回车之外的字符 ?0-1个字符 量词 只有前面是元字符,才变现量词 * 0-n 量词 /^\d+$/ 以字符开头,义字符结尾 [0-9] ...
- c# string.Format用法总结
文章出处:http://www.cnblogs.com/7788/archive/2009/05/13/1455920.html 先举几个简单的应用案例: 1.格式化货币(跟系统的环境有关,中文系统默 ...
- DevExpress licenses.licx 问题
在DevExpress ( 当然并不范指DevExpress,很多收费软件都是这样的)中,licenses.licx 是用户许可证书文件,当我们使用某些ActiveX(是Microsoft对于一系列策 ...
- 2014多校第三场1005 || HDU 4891 The Great Pan(模拟)
题目链接 题意 : 给你n行字符串,问你有多少种理解方式.有两大类的理解 (1){A|B|C|D|...}代表着理解方式可以是A,可以是B或C或者D. (2)$blah blah$,在$$这两个符号中 ...
- 编程实现linux下的shell
/************************************************************************* > File Name: Kris_shel ...
- Windows SEH学习 x86
windows 提供的异常处理机制实际上只是一个简单的框架.我们通常所用的异常处理(比如 C++ 的 throw.try.catch)都是编译器在系统提供的异常处理机制上进行加工了的增强版本.这里先抛 ...
- Js之DOM(一)
----------------------------------------------------------------------------------------------第一部分 D ...
- MongoDB (三) MongoDB 安装
MongoDB安装在Windows上 在 Windows上,首先要安装 MongoDB下载最新发布的MongoDB: http://www.mongodb.org/downloads 确保得到正确的版 ...
- FastDFS之java客户端使用
为了方便应用程序的访问FastDFS,官网提供了fastdfs-client-java,以便更好的与应用程序结合使用. 下载fastdfs-client-java源码添加到项目工程里面,添加配置文件: ...
- Java基础复习之二:运算符,键盘录入,流程控制语句,if语句,三元运算
1.运算符 1.1.算术运算符 +(加法有三个用法:加法,正号,字符串连接符) - * / % ++ -- 1.1.1./ 是取商,%是取余 1.1.2.++ 与--的用法(a:作用是自 ...