文件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. 关闭输入流 说明:其 ...
随机推荐
- dd大牛的《背包九讲》
P01: 01背包问题 题目 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 基本思路 这是最 ...
- Java异步消息平台
l JAVA平台异步消息模块 JAVA平台异步消息模块,是一个针对RabbitMQ的消息发送及处理封装,包含消息的配置.发送.接收.失败重试.日志记录等,总共分为4个部分: 1)RabbitMQ访问 ...
- java集合TreeMap应用---求一个字符串中,每一个字母出现的次数
package cn.itcast.p1.map.test; import java.util.Iterator; import java.util.Map; import java.util.Tre ...
- Visual Studio 快捷键
Visual Studio 快捷键 CTRL + DELETE 删除至词尾 CTRL + BACKSPACE 删除至词头Ctrl+Shift+L: 删除当前行 Ctrl+K+Crtr+C: 注释选定内 ...
- (1)搭建opencv-android环境
前言: 本文目的是指导在windows平台搭建一个opencv for android 的开发环境,作者参考了很多网上的教程,本文所使用的各种软件.插件都是截止到写这篇文章的最新版本,作者在实际搭建环 ...
- android模拟器(genymotion)+appium+python 框架执行过程中问题解答
1.case运行过程中中文输入不进去? 答:注意事项 1)需要修改系统编码为utf-8,才能解决中文输入问题,case执行入口文件添加代码如下: import sys reload(sys) sys. ...
- 常用搜索引擎的算分,你get了嘛?
搜索引擎发展至今,已公布了多种算法.作为SEOER的你,还不懂,就out啦.懂了不会用,也是然并卵的一种行为.了解算法知识并不懂得如何把算法实践于SEO工作的你,还是处于学生思维,是时候该升级了.且听 ...
- ECharts案例教程1
原文:http://blog.csdn.net/whqet/article/details/42703973 简介 ECharts,缩写来自Enterprise Charts,商业级数据图表,是百度的 ...
- 可运行jar包生成步骤和jar包的生成
一.可运行jar包生成步骤 1.进入.class文件所在目录,新建一个记事本文件,假设为1.txt,文件内容: 1> Main-Class:可运行类的名字 ( 例如:Main-Class:T ...
- 添加dubbo xsd的支持
使用dubbo时遇到问题: org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'htt ...