Linux环境编程之文件I/O(三):文件的读写

(一)

当我们打开了一个文件后,一般对文件的操作就是读写。读写函数分别是read、write。

       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);

参数:

fd:利用open、creat得到的文件描述符。

buf:buf是void *类型,用于表示通用指针,此处指所读取到的数据的内存缓冲。

count:需要读取的数据量。

返回值:成功执行时,返回所读取的数据的字节数,一般等于或小于所请求读取的数据字节数。若已到文件结尾则返回0,若出错则返回-1。失败返回-1时,error被设为以下的某个值。这个error一般是在内核里的驱动程序中设置的,不是应用程序设置的。

EAGAIN:打开文件时设定了O_NONBLOCK标志,并且当前没有数据可读取
EBADF:文件描述词无效,或者文件不可读
EFAULT:参数buf指向的空间不可访问
EINTR:数据读取前,操作被信号中断
EINVAL:一个或者多个参数无效
EIO:读写出错
EISDIR:参数fd索引的时目录

上面提到返回值可能小于所请求读取的字节数。原因可能是:

1、读普通文件时,在读到要求字节数之前已到达了文件尾端。

2、当从终端设备读时,通常一次最多读一行。

3、当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。

4、当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数。

5、当从某些面向记录的设备读时,一次最多返回一个记录。

6、当某一信号造成中断,而已经读了部分数据时。(以后会在信号部分详细讨论该情况)

(二)

       #include <unistd.h>
       ssize_t write(int fd, const void *buf, size_t count);

write函数与read函数相对,是向打开的文件写数据。

参数:

fd:利用open、creat得到的文件描述符。

buf:buf是void *类型,用于表示通用指针,此处指所写入的数据的内存缓冲。

count:需要写入的数据量。

返回值:若成功则返回已写的字节数,若出错则返回-1。

注意:对于普通文件,写操作从文件的当前偏移量处开始。如果在打开该文件时,指定了O_APPEND选项,则在每次写操作之前,将文件偏移量设置在文件的当前结尾处。在一次成功写之后,该文件偏移量增加实际写的字节数。

(三)

上面write函数中的注意部分,有“文件的当前偏移量处”的描述,如果我想从文件的开始处或文件的结尾处写数据该如何操作呢?这就用到了另外一个I/O函数lseek函数。

其实,每个打开的文件都有一个与其相关联的“当前文件偏移量”。它通常是一个非负整数,用以度量从文件开始处计算的字节数。通常,读写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数。系统默认情况下,当打开一个文件时,除非指定O_APPEND选项,否则该偏移量被设置为0。

       #include <sys/types.h>
       #include <unistd.h>
       off_t lseek(int fd, off_t offset, int whence);

参数:

filedes:利用open、creat得到的文件描述符。

offset与whence有关,whence有三个SEEK_SET、SEEK_CUR、SEEK_END。

1、若whence是SEEK_SET,则将该文件的偏移量设置为距文件开始处offset个字节。

2、若whence是SEEK_CUR,则将该文件的偏移量设置为其当前值加offset,offset可正可负。

3、若whence是SEEK_END,则将该文件的偏移量设置为文件长度加offset,offset可正可负。

返回值:若成功则返回新的文件偏移量,若出错则返回-1。

注意:

1、并不是所有的文件都能设置文件偏移量,对于管道、FIFO、网络套接字等不能设置文件偏移量。可用下列方法做判断:

off_t currpos;
currpos = lseek(fd, 0, SEEK_CUR);
若返回值为-1,则不能设置文件偏移量,并将error设置为ESPIPE。
2、因为偏移量可能是负值,所以在比较lseek的返回值时应当谨慎,不要测试它是否小于0,而要测试它是否等于-1。

if(lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
3、lseek仅将文件偏移量记录在内核中,它并不引起任何I/O操作。然后,该偏移量用于下一个读写操作。文件偏移量可以大于文件的当前长度,可在文件中构成一个空洞,文件中的空洞并不要求在磁盘上占用存储区。
(四)

/*
 *File Name:demo.c
 *Author   :libing
 *Mail     :libing1209@126.com
 *function :read、write、lseek
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define BUFFSIZE 2048

int
main(void)
{
	int fd;
	char buf[BUFFSIZE] = {0, 1, 2, 3};
	ssize_t nbytes;
         //创建新的文件test.txt
	fd = open("test.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
	if(fd == -1){
		printf("creat test.txt failed.\n");	
		exit(1);
	}
         //写数据到文件
	nbytes = write(fd, buf, BUFFSIZE);
	if(nbytes == -1){
		printf("read failed.\n");	
	}
        //为打开的文件设置偏移量到文件开始处
	if(lseek(fd, 0, SEEK_SET) == -1){
		printf("cannot seek\n");	
	}
         //读文件数据
	nbytes = read(fd, buf, BUFFSIZE);
	if(nbytes == -1){
		printf("read failed.\n");	
	}
	printf("nbytes = %d.\n", nbytes);

	return 0;
}
编译测试结果:

编译程序:
gcc demo.c
运行程序:
./a.out
结果显示:
nbytes = 2048.
(五)

应用举例:

Linux中,我们经常使用cp命令复制一个文件内容到另一个文件中,如cp file1 file2。复制的命令,我们就可以用文件I/O来完成

/*
 *File Name  : copy.c
 *Author     : libing
 *Mail       : libing1209@126.com
 *Function   : copy file1 to file2
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

int
main(int argc, char *argv[])
{
	int file1fd;
	int file2fd;
	char buf[2048];
	int nbytes;

	if(argc != 3){
		printf("usage %s file1 file2.\n", argv[0]);	
		return 0;
	}
        //源文件,即要复制的文件file1
	file1fd = open(argv[1], O_RDONLY);
	if(file1fd == -1){
		printf("open file1 failed.\n");	
		return 0;
	}
        //目的文件,即要复制到的文件file2
	file2fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
	if(file2fd == -1){
		printf("open file2 failed.\n");	
		return 0;
	}
        //进行文件的复制
	while((nbytes = read(file1fd, buf, 2048)) > 0)
		write(file2fd, buf, nbytes);


	close(file1fd);
	close(file2fd);
	
	return 0;
}
编译结果测试
编译文件:
gcc copy.c
执行文件:
./a.out demo.c test.txt
显示结果:vi test.txt 可以看到其内容与demo.c内容相同。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值