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

来源:互联网 发布:知乎 王家卫 章子怡 编辑:程序博客网 时间:2024/04/29 23:01

(一)

当我们打开了一个文件后,一般对文件的操作就是读写。读写函数分别是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 2048intmain(void){int fd;char buf[BUFFSIZE] = {0, 1, 2, 3};ssize_t nbytes;         //创建新的文件test.txtfd = 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>intmain(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;}        //源文件,即要复制的文件file1file1fd = open(argv[1], O_RDONLY);if(file1fd == -1){printf("open file1 failed.\n");return 0;}        //目的文件,即要复制到的文件file2file2fd = 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内容相同。





0 0
原创粉丝点击