文件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. 关闭输入流 说明:其 ...
随机推荐
- POJ 2001
#include<iostream> using namespace std; ; struct trienode { trienode * next[kind]; int branch; ...
- 优雅的python 写排序算法
arr=[] while True: #输入数据 当输入q结束 a=raw_input() if a=="q": break arr.append(int(a)) s=len(ar ...
- Linux网络编程6——使用TCP实现文件服务器
需求 当客户端连接上服务器后,服务器会将相应文件传输给客户端,实现文件下载. 思路 服务器端,主进程负责listen.循环内,主进程每从任务请求队列中accept出一个请求,就fork出孙子完成文件传 ...
- C Primer Plus之结构和其他数据形式
声明和初始化结构指针 声明结构化指针,例如: struct guy * him; 初始化结构指针(如果barney是一个guy类型的结构),例如: him = &barney; 注意:和数组不 ...
- 关于null == 0?返回false的问题
1.首先我们先看各种情况的结果: null > 0? //=>false null < 0? //=>false null >= 0? //=>true null ...
- 第一个React程序HelloWorld
一.程序步骤 1.用React.createClass生成组件 2.调用React.render把组件渲染到页面中,dom的操作由react自动完成 二.代码 <!DOCTYPE html> ...
- WaitForSingleObject与WaitForMultipleObjects用法详解(好用,而且进入一个非常高效沉睡状态,只占用极少的CPU时间片)
在多线程下面,有时候会希望等待某一线程完成了再继续做其他事情,要实现这个目的,可以使用Windows API函数WaitForSingleObject,或者WaitForMultipleObjects ...
- 我们为什么需要DTO(数据传输对象)
原文:http://www.cnblogs.com/Gyoung/archive/2013/03/23/2977233.html DTO即数据传输对象(Data Transfer Object).之前 ...
- Docker基础技术:Linux Namespace(上)
时下最热的技术莫过于Docker了,很多人都觉得Docker是个新技术,其实不然,Docker除了其编程语言用go比较新外,其实它还真不是个新东西,也就是个新瓶装旧酒的东西,所谓的The New “O ...
- openfire插件开发1
http://www.cnblogs.com/hoojo/archive/2013/03/29/openfire_plugin_chatlogs_plugin_.html http://www.cnb ...