三、文件IO——系统调用(续)
3.2.4 read 函数--- 读文件
read(由已打开的文件读取数据)
#include<unistd.h>
ssize_t read(int fd, void * buf, size_t count);
- * 函数说明
- read() 会把参数 fd 所指的文件传送 count 个字节到 buf 指针所指的内存中。
- 若参数 count 为0,则 read() 不会有作用并返回0.
- 返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动
- * 参数
- fd 为先前由 open() 或 creat() 所返回的文件描述词。
- buf 存放读取数据的缓存
- count 要求读取一次数据的字节数
- * 附加说明
- 如果顺利 read() 会返回实际读到的字节数,最好能将返回值与参数 count 做比较,若返回的字节数要比要求读到的字节数少,则有可能读到了文件尾、从管道(pipe)或终端机读取,或者是 read() 被信号中断了读取动作。当有错误发生时,则返回 -1,错误代码存入 errno 中,而文件读写位置则无法预期,
- * 错误代码
- EINTR 此调用被信号所中断
- * EAGAIN 当使用不可阻断 I/O 时(O_NONBLOCK),若无数据可读取则返回此值
- * EBADF 参数 fd 非有效的文件描述词,或该文件已关闭
- 由多种情况可使实际督导的字节数少于要求读写字节数
- 读普通文件时,在读到要求字节数之前已到达了文件尾端
- 当从终端设备读时,通常一次最多读一行
- 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数
- 某些面向记录的设备,例如磁带,一次最多返回一个记录
- 进程由于信号造成中断
- 读操作从文件的当前位移量处开始,在成功返回前,该位移量增加实际读得的字节数
3.2.5 write 函数--- 写文件
write(将数据写入已打开的文件内)
#include<unistd.h>
ssize_t read(int fd, void * buf, size_t count);
- * 相关函数 open,read,fcntl,close,lseek,sync,fsync,fwrite
- * 函数说明
- write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。当然,文件读写位置也会随之移动。
- write 出错的一个常见原因是:磁盘已写满,或者超过了对一个给定进程的文件长度限制
- 对于普通文件,写操作从文件的当前位移量处开始。如果在打开该文件时,指定了 O_APPEND 选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处。在一次成功写之后,该文件位移量增加实际写的字节数。
- * 返回值
- 如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
- 返回值通常与参数 count 的值不同,如果不一样则表示出错
- * 错误代码
- EINTR 此调用被信号所中断
- * EAGAIN 当使用不可阻断 I/O 时(O_NONBLOCK),若无数据可读取则返回此值
- * EBADF 参数 fd 非有效的文件描述词,或该文件已关闭
3.2.6 lseek 函数--- 文件定位
#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fildes,off_t offset ,int whence);
- * 相关函数 dup,open,fseek
- 函数功能:
- 定位一个已打开的文件
- * 函数说明
- 每一个已打开的文件都有一个读写位置,当打开文件时通常其读写位置是指向文件开头,若是以附加的方式打开文件(如O_APPEND),则读写位置会指向文件尾。当read()或write()时,读写位置会随之增加,lseek()便是用来控制该文件的读写位置。
- * 参数:
- @fildes 已打开的文件描述符
- * @offset 位移量。根据参数whence来移动读写位置的位移数。
- @ whence 定位的位置,为下列其中一种:
- * SEEK_SET 将该文件的位移量设置为距离文件开始处 offset 个字节
- * SEEK_CUR 将该文件的位移量设置为其当前值处 加offset 个字节,offset 可为正或负
- * SEEK_END 将该文件的位移量设置为文件长度 加offset 个字节,offset 可为正或负
- * 当whence 值为SEEK_CUR 或SEEK_END时,参数offet允许负值的出现
- * 返回值
- 若成功则返回新的文件位移量(绝对偏移量),若出错返回-1.
- * 特别使用方式
- * 1) 欲将读写位置移到文件开头时:lseek(int fildes,0,SEEK_SET);
- * 2) 欲将读写位置移到文件尾时:lseek(int fildes,0,SEEK_END);
- * 3) 想要取得目前文件位置时:lseek(int fildes,0,SEEK_CUR);
- * 附件说明
- Linux系统不允许lseek()对tty装置作用,此项动作会令lseek()返回ESPIPE。
- 其他使用方式:
- lseek 也可用来确定所涉及的文件是否可以设置位移量。如果文件描述符引用的是一个管道或FIFO,则 lseek 返回 -1,并将 errno 设置为 EPIPE
- 每个打开文件都由一个与其相关联的“当前文件偏移量”。它是一个非负整数,用以度量从文件开始处计算的字节数。通常,读、写操作都从当前文件偏移量处开始,并使偏移量增加所读或写的字节数。按系统默认,当打开一个文件时,除非指定 O_APPEND 选择项,否则该位移量被设置为0
3.3 例子
3.3.1 文件读写
io.h
#ifndef __IO_H__
#define __IO_H__ extern void copy(int fdin, int fdout); #endif
io.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "io.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> #define BUFFER_LEN 1024 /* 文件的读写拷贝 */
void copy(int fdin, int fdout)
{
char buff[BUFFER_LEN];
ssize_t size; while((size = read(fdin, buff, BUFFER_LEN)) > ) { //从 fdin 中读取 BUFFER_LEN 个字节存放入 buff 中
if(write(fdout, buff, size) != size) {
fprintf(stderr, "write error: %s\n", strerror(errno));
exit();
}
}
if(size < ) {
fprintf(stderr, "read error:%s\n", strerror(errno));
exit(); // 相当于 return 1;
}
}
将 io.c 编译成 .o 文件,供其他模块进行调用
gcc -o obj/io.o -Iinclude -c src/io.c
- -o:指定输出的目录和文件格式
- -Iinclude:指定包含的头文件目录,-I使指定包含头文件,后面的inlcude 即是头文件所在的目录,也可以采用绝对路径
- -c:指定源文件
cp.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "io.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> int main(int argc, char *argv[])
{
if(argc != ) {
fprintf(stderr, "usage: %s srcfile destfile\n", argv[]);
exit();
} int fdin;
int fdout; //打开一个待读取的文件
fdin = open(argv[], O_RDONLY);
if(fdin < ) {
fprintf(stderr, "open error: %s\n", strerror(errno));
exit();
} else {
printf("open file: %d\n", fdin);
} //打开一个待写入的文件
fdout = open(argv[], O_WRONLY | O_CREAT | O_TRUNC, );
if(fdout < ) {
fprintf(stderr, "open error: %s\n", strerror(errno));
exit();
} else {
printf("open file: %d\n", fdout);
} //文件复制
copy(fdin, fdout); close(fdin);
close(fdout); return ;
}
编译:
gcc -o bin/cp -Iinclude obj/io.o src/cp.c
运行:
3.3.2 lseek 文件定位
(1)例子1
打印要读取的文件的总的大小
每次写完后,文件定位的位置
io.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "io.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> #define BUFFER_LEN 1024 /* 文件的读写拷贝 */
void copy(int fdin, int fdout)
{
char buff[BUFFER_LEN];
ssize_t size; // printf("file length: %ld\n", lseek(fdin, 0L, SEEK_END));//将文件定位到文件尾部,偏移量为0L
// lseek(fdin, 0L, SEEK_SET);// 定位到文件开头 while((size = read(fdin, buff, BUFFER_LEN)) > ) { //从 fdin 中读取 BUFFER_LEN 个字节存放入 buff 中
printf("current: %ld\n", lseek(fdin, 0L, SEEK_CUR)); //打印当前位置 if(write(fdout, buff, size) != size) {
fprintf(stderr, "write error: %s\n", strerror(errno));
exit();
}
}
if(size < ) {
fprintf(stderr, "read error:%s\n", strerror(errno));
exit(); // 相当于 return 1;
}
}
cp.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "io.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> int main(int argc, char *argv[])
{
if(argc != ) {
fprintf(stderr, "usage: %s srcfile destfile\n", argv[]);
exit();
} int fdin;
int fdout;
off_t ret; //打开一个待读取的文件
fdin = open(argv[], O_RDONLY);
if(fdin < ) {
fprintf(stderr, "open error: %s\n", strerror(errno));
exit();
} else {
printf("open file: %d\n", fdin);
} 32 ret = lseek(fdin, 0L, SEEK_END); //将文件定位到文件末尾
33 if(ret == -1) {
34 fprintf(stderr, "lseek error: %s\n", strerror(errno));
35 exit(1);
36 }
37 printf("file length: %ld\n", ret);
38
39 ret = lseek(fdin, 0L, SEEK_SET);// 定位到文件开头
40 if(ret == -1) {
41 fprintf(stderr, "lseek error: %s\n", strerror(errno));
42 exit(1);
43 } //打开一个待写入的文件
fdout = open(argv[], O_WRONLY | O_CREAT | O_TRUNC, );
if(fdout < ) {
fprintf(stderr, "open error: %s\n", strerror(errno));
exit();
} else {
printf("open file: %d\n", fdout);
} //文件复制
copy(fdin, fdout); close(fdin);
close(fdout); return ;
}
编译:
gcc -o bin/cp -Iinclude src/io.c src/cp.c
执行:
(2)空洞文件制作
空洞文件就是从文件尾部跳出若干个字节再写入信息,中间空出来的信息就是一个空洞
hole_file.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> //生成空洞文件
char *buff = ""; int main(int argc, char *argv[])
{
if(argc < ) {
fprintf(stderr, "usage: %s [file]\n", argv[]);
exit();
} int fd;
size_t size; fd = open(argv[], O_WRONLY | O_CREAT | O_TRUNC, );
if(fd < ) {
perror("open error");
exit();
} // 写入多少个字节,一个字符串占多少个字节
size = strlen(buff) * sizeof(char); // 将字符串写入到空洞文件中
if(write(fd, buff, size) != size) {
perror("write error");
exit();
} // 定位到文件尾部的 10 个字节处
if(lseek(fd, 10L, SEEK_END) == -) {
perror("lseek error");
exit();
} // 从文件尾部的10个字节处再写入字符串
if(write(fd, buff, size) != size) {
perror("write error");
exit();
} close(fd);
return ; }
编译:
gcc -o bin/hole_file src/hole_file.c
执行:
三、文件IO——系统调用(续)的更多相关文章
- 三、文件IO——系统调用
3.1 文件描述符 文件IO 系统调用是不带缓存的,文件 I/O 系统调用不是 ANSI C 的组成部分,是 POSIX 的组成部分. 系统调用与C库: C库函数的IO 的底层还是调用系统调用 I/O ...
- Java 文件IO续
文件IO续 File类 用来将文件和文件夹封装成对象 方便对文件和文件夹的属性信息进行操作 File对象可以作为参数传递给流的构造函数 Demo1 File的构造方法 public cla ...
- 文件IO——将文件dfs的文件内容第三个字节之后的内容复制到文件dfd中
/* 使用文件IO将文件fds中的内容复制到文件fdd中去 1.创建两个文件描述符 2.使用open()方法分别以只读只写方式将文件描述符符文件连接 3.将读位置后移三位 4.将fds内容存储到缓冲区 ...
- select、poll、epoll三组IO复用
int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout)//其中n ...
- 文件IO函数和标准IO库的区别
摘自 http://blog.chinaunix.net/uid-26565142-id-3051729.html 1,文件IO函数,在Unix中,有如下5个:open,read,write,lsee ...
- (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- 文件IO
在unix世界中视一切为文件,无论最基本的文本文件还是网络设备或是u盘,在内核看来它们的本质都是一样的.大多数文件IO操作只需要用到5个函数:open . read . write . lseek 以 ...
- UNIX高级环境编程(14)文件IO - O_DIRECT和O_SYNC详解 < 海棠花溪 >
春天来了,除了工作学习,大家也要注意锻炼身体,多出去运动运动. 上周末在元大都遗址公园海棠花溪拍的海棠花. 进入正题. O_DIRECT和O_SYNC是系统调用open的flag参数.通过指定o ...
- (代码篇)从基础文件IO说起虚拟内存,内存文件映射,零拷贝
上一篇讲解了基础文件IO的理论发展,这里结合java看看各项理论的具体实现. 传统IO-intsmaze 传统文件IO操作的基础代码如下: FileInputStream in = new FileI ...
随机推荐
- Bomb HDU - 5934 (Tarjan)
#include<map> #include<set> #include<ctime> #include<cmath> #include<stac ...
- Dividing the Path POJ - 2373(单调队列优化dp)
给出一个n长度的区间,然后有一些小区间只能被喷水一次,其他区间可以喷水多次,然后问你要把这个区间覆盖起来最小需要多少喷头,喷头的半径是[a, b]. 对于每个只能覆盖一次的区间,我们可以把他中间的部分 ...
- 【php】php实现数组分块
有时候需要将一个大数组按一定大小分块,那么可以实现这个功能,代码如下: /** * @param array $arr * @param int $size <p> * @param bo ...
- 哈尔滨工程大学ACM预热赛 G题 A hard problem(数位dp)
链接:https://ac.nowcoder.com/acm/contest/554/G Now we have a function f(x): int f ( int x ) { if ( ...
- 洛谷P4307 球队收益
题意:有n个球队,m场比赛. 每个球队都已经有些胜负场次了. 每个球队的收益为Ci * wini2 - Di * losei2. 求最小可能总收益. 解: 先看出一个模型:用一流量代表一个胜场,每场比 ...
- Dreamweaver - <!DOCTYPE html>
最近设计网页,很多使用 <!DOCTYPE html> 关于<!DOCTYPE html>的详细介绍: http://www.w3school.com.cn/tags/tag_ ...
- numpy学习之前的必要数学知识:线性代数
行列式 主要内容 1.行列式的定义及性质 2.行列式的展开公式 一.行列式的定义 1.排列和逆序 排列:由n个数1,2,…,n组成的一个有序数组称为一个n级排列,n级排列共有n!个 逆序:在一个排列中 ...
- JS事件(三)部分常用事件
1.滚动条事件scroll EventUtil.addHandler(window,"scroll",function(event){ if(document.compatMode ...
- E212: Can't open file for writing
意思是不能保存. 原因是权限不够,普通用户用vi 进行不了保存,需要使用超级用户才可以 命令:sudo su 转换成超级用户 vi hello 打开文件 :wq 即可保存退出
- HTML学习笔记Day14
一.移动端页面布局 1.移动端的屏幕尺寸 移动端屏幕尺寸:屏幕对角线的长度,单位是英寸(1英寸=2.45厘米): 常见的尺寸有:2.4,2.8,3.5,3.7,4.2,5.0,5.5,6.0 2.屏幕 ...