您的位置:首页 > 其它

文件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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: