文件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. 关闭输入流 说明:其 ...
随机推荐
- UVA 11609 Teams 组合数学+快速幂
In a galaxy far far away there is an ancient game played among the planets. The specialty of the gam ...
- AngularJS学习笔记2——AngularJS的初始化
本文主要介绍AngularJS的自动初始化以及在必要的适合如何手动初始化. Angular <script> Tag 下面通过一小段代码来介绍推荐的自动初始化过程: <!doctyp ...
- Android 核心分析之十三Android GWES之Android窗口管理
Android GWES之Android窗口管理1基本构架原理 Android的窗口管理是C/S模式的.Android中的Window是表示Top Level等顶级窗口的概念.DecorView是Wi ...
- linux shell 命令学习(2) paste - merge lines of files
paste - merge lines of files 命令格式: paste [OPTION] ... [FILE] ... 说明: 输出每个文件的对应行组合而成的行,中间用tab分开,如果没有F ...
- Android开发常用代码片段
拨打电话 public static void call(Context context, String phoneNumber) { context.startActivity( new Inten ...
- Android TabHost中Activity之间传递数据
例子1: TabHost tabhost = (TabHost) findViewById(android.R.id.tabhost); tabhost.setup(this.getLocalActi ...
- highcharts联合jquery ajax 后端取数据
Highcharts是一个制作图表的纯Javascript类库,主要特性如下: 兼容性:兼容当今所有的浏览器,包括iPhone.IE和火狐等等: 对个人用户完全免费: 纯JS,无BS: 支持大部分的图 ...
- c# 计算1-100之间的所有奇数的和
求1-100之间所有奇数整数和: class Program { static void Main(string[] args) { ,); Console.WriteLine("1-100 ...
- 截取usb数据包,控制usb设备----Relay设备
在项目开发当中,我们需要一个usb转继电器的设备当开关控制无线发射设备,采购部采购时并未详细了解Relay设备的运行环境就买了一批设备,之后发现设备厂家只提供了windows库,而我们是要在linux ...
- 《c程序设计语言》读书笔记--字符串比较
举例如下: char a[10]; 1.定义的时候直接用字符串赋值 char a[10]="hello"; 注意:不能先定义再给它赋值,如 char a[10]; a[10]= ...