文件IO的基本操作(二)
2014-09-28 18:36
155 查看
文件IO的基本操作(二)
本文将介绍unix系统中,文件的基本操作读和写,read、write和sleek函数.1.读取数据 read函数
在上一篇文章中,介绍了文章的打开,创建和关闭等函数,有了前一步的基础,进一步学习读写操作。打开文件后,该干嘛,该干嘛就干嘛呗.先来读取文件内容吧.头文件:#include<unistd.h>
定义函数:
ssize_t read(int filedes,void *buf size_t nbytes);
函数说明:
参数filedes,文件描述符fd.
参数buf,存储数据的内存空间,数据类型为通用指针.
参数nbytes,空间大小,类型为不带符号的整数.
read()函数会根据fd所指文件读取该文件数据,读取的大小为nbytes个字节,然后将读取到的数据存放到buf指针所指的内存.
返回值:若参数nbytes为0,则read()不会有任何作用并返回0;若nbytes>0,则返回实际读取到的字节数,若已到文件结尾(nbytes>文件内容字节数)则返回返回0,若出错返回-1,错误代码存入errno中,而文件读写位置则无法预知.
如果成功执行read()会哦返回实际读取到的字节数,但最好能将返回值与参数nbytes作比较,若返回的字节数比要求读取的字节数少,则有可能读到了文件尾.
例子1:用read函数读取文件内容,并输出到标准输出.
#include<fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define BUFFSIZE 4096 void main() { int fd; int count; char buf[BUFFSIZE]; //打开文件 fd = open("data.txt", O_RDWR, 0666); if(fd==-1) { printf("open file error:%m\n"); exit(-1); } //读取文件数据 count = read(fd,buf,BUFFSIZE); buf[count-1]='\0'; printf("count:%d\ncontent:%s\n",count,buf); //关闭文件 close(fd); }输出:
:count:89
:content:Advanced Programming int the UNIX Environment!writed by W.Richard Stevens Stephen A.Rago
例子2:在例子1的基础上,用read函数两次读取文件内容,并输出到标准输出.
#include<fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define BUFFSIZE 4096 void main() { int fd; int count; char buf[BUFFSIZE]; //打开文件 fd = open("data.txt", O_RDWR); if(fd==-1) { printf("open file error:%m\n"); exit(-1); } //第一次读取文件数据 count = read(fd,buf,BUFFSIZE); buf[count-1]='\0'; printf("count:%d\ncontent:%s\n",count,buf); //第二次读取文件数据 buf[0]='\0'; count = read(fd,buf,BUFFSIZE); buf[count-1]='\0'; printf("count:%d\ncontent:%s\n",count,buf); //关闭文件 close(fd); }输出:
:count:89
:content:Advanced Programming int the UNIX Environment!writed by W.Richard Stevens Stephen A.Rago
:count:0
:content:
由于第一次读取时,已经读取到文件尾端,故第二次读取时,read函数会返回0.
2.写数据 write函数
上述已介绍如何从文件中读取数据,那又如何往文件里写数据呢?调用write函数向打开的文件写入数据.头文件:#include<unistd.h>
定义函数:ssize_t write(int filedes, const void *buf, size_t nbytes)
函数说明:
参数filedes,文件描述符fd.
参数buf,存储数据的内存空间,数据类型为通用指针.
参数nbytes,空间大小,类型为不带符号的整数.
write()函数会根据文件描述符fd,将参数buf所指内存中的内容写入fd所指文件,大小为nbytes,写入成功后文件的读写位置也会随之改变,对于普通文件,写操作从文件的当前偏移量处开始(光标位置).如果在打开文件是时,指定了O_APPEND选项,则每次写操作之前,将文件偏移量设置在文件的当前结尾处,就是在文件结尾处追加待写的数据.
返回值:函数的返回值通常与参数nbytes相同,否则表示出错.write出错的一个常见的原因:磁盘已写满,或者超过了一个给定进程的文件长度限制.
例子3:使用write函数,将一字符串写入文件中.
#include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define BUFFSIZE 4096 void main() { int fd; int count; char buf[BUFFSIZE] = "UNIX Environment!"; fd = open("write.txt", O_RDWR|O_CREAT, 0666); if(fd==-1) { printf("open file error:%m\n"); exit(-1); } //写数据 count = write(fd, buf, strlen(buf)); if(count==-1) { printf("open file error:%m\n"); exit(-1); } printf("count:%d\nsize:%d\n",count,strlen(buf)); close(fd); }
输出:
:在write.txt文件中将会有一字符串UNIX Environment!
例子4:使用read和write函数,复制一个文件.
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #define BUFFSIZE 4096 void main() { int n; char buf[BUFFSIZE]; while((n = read(STDIN_FILENO,buf, BUFFSIZE))>0) { if(write(STDOUT_FILENO,buf,n)!=n) { printf("write error\n"); } } if(n<0) printf("read error\n"); exit(0); }输出:
:在输入窗口上输入字符,按回车,输入的数据会复制输出.
3.读写偏移量 lseek函数
每个打开的文件都有一个与其相关联的“当前文件偏移量”.它通常是一个非负整数,用以度量从文件开始计算的字节数.通常,读写操作都从当前文件偏移量开始,并使偏移量增加所读写的字节数.若文件以附加的形式打开(指定O_APPEND),读写位置会指向文件尾.头文件:#include<unistd.h>
定义函数:off_t lseek(int filedes, off_t offset, int whence);
函数说明:
参数filedes,文件描述符fd.
参数offset,对于该参数的解析与参数. whence的值有关
参数whence为下列其中一种:
SEEK_SET 将该文件的偏移量位置设置为距文件开始出offset个字节,即参数offset为新的读写位置.
SEEK_CUR 将该文件的偏移量位置设置为其目前的读写位置加offset 个位移量offset可为正或负.
SEEK_END 将读写位置指向文件尾后再增加offset 个位移量.
当whence 值为SEEK_CUR 或SEEK_END 时, 参数offet 允许负值的出现.
返回值:当调用成功时则返回目前的读写位置, 也就是距离文件开头多少个字节. 若有错误则返回-1, errno 会存放错误代码. lseek 的以下用法返回当前的偏移量:
off_t currpos; currpos = lseek(fd, 0, SEEK_CUR);currpos值可以判断操作是否可以改变某个文件的偏移量.如果参数文件描述符fd指定的是 pipe(管道)、FIFO 或者 socket,则lseek 返回-1 并且置 errno 为 ESPIPE.
对于普通文件,当前文件偏移量是一个非负整数.但对于特殊设备,前文件偏移量有可能是负数.因此,我们不能简单地测试 lseek 的返回值是否小于 0 来判断 lseek 成功与否,而应该测试 lseek 的返回值是否等于-1来判断 lseek 成功与否.
lseek 仅将前文件偏移量保存于内核中,不会导致任何 I/O 操作.这个前文件偏移量将被用于之后的读写操作.
如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大” ,中间没有数据.这就是所谓的在文件里创造“空洞”.没有被实际写入文件的所有字节由重复的 0 表示.空洞是否占用硬盘空间是由文件系统决定的.
特殊使用情况:
1) 欲将读写位置移到文件开头时:lseek(int fildes, 0, SEEK_SET);
2) 欲将读写位置移到文件尾时:lseek(int fildes, 0, SEEK_END);
3) 想要取得目前文件位置时:lseek(int fildes, 0, SEEK_CUR);
错误代码:
EBADF: fildes不是一个打开的文件描述符.
ESPIPE:文件描述符被分配到一个管道、套接字或FIFO.
EINVAL:whence取值不当
附加说明:
Linux系统不允许lseek()对tty装置作用,此项动作会令lseek()返回ESPIPE.
SEEK_SET 等同于数字0 例如 :lseek(int fildes,0,SEEK_SET);=lseek(int fildes,0,0).
SEEK_CUR 等同于数字1 例如 :lseek(int fildes,0,SEEK_CUR);=lseek(int fildes,0,1).
SEEK_END 等同于数字2 例如 :lseek(int fildes,0,SEEK_END);=lseek(int fildes,0,2).
例子5,使用lseek读取指定偏移量上的数据.
#include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define BUFFSIZE 6 void main() { int fd; char name[BUFFSIZE]; int i; int r; fd = open("db.txt",O_RDWR); if(fd==-1) { printf("open file error:%m\n"); exit(-1); } for(i=0; i<3; i++) { r = lseek(fd, i*23, SEEK_SET); r = lseek(fd, 4, SEEK_CUR); read(fd, name, BUFFSIZE); printf("当前偏移量:%d\n",r); printf("读取到的name:%s\n",name); } close(fd); }输出:
:前偏移量:4
:读取到的name:a
:当前偏移量:27
:读取到的name:Hong
:当前偏移量:50
:读取到的name:gMing
相关文章推荐
- IO-File 文件 目录 基本操作 递归 遍历
- C# 文件与目录的基本操作(System.IO)
- 输入输出流(IO)—文件字节流(FileInputStream & FileOutputStream)的基本操作及运用
- 2011-08-30 交作业(java io 文件基本操作)
- C# 文件与目录的基本操作(System.IO)
- java_IO_文件的基本操作
- C# 文件与目录的基本操作(System.IO)
- Java IO-基本文件写操作
- [Linux]--标准文件 IO 基本操作
- 输入输出流(IO)—文件字符流(FileReader & FileWriter)的基本操作及应用
- Java IO 基本文件读操作
- IO容器与文件操作(二)File类的基本操作
- 文件的一些基本操作
- ◎Vbs脚本编程简明教程之十一 ——FSO中文件的基本操作
- C# 对sharepoint 列表的一些基本操作,包括添加/删除/查询/上传文件给sharepoint list添加数据
- C#文件IO操作
- UNIX 文件系统基本操作
- 使用java.io.*操作文件的拆分与合并,Application一例!
- C++基本文件操作
- C# 基本文件操作