三、文件IO——系统调用(续)

3.2.4 read 函数--- 读文件

  read(由已打开的文件读取数据)

1 #include<unistd.h>
2  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(将数据写入已打开的文件内)

1 #include<unistd.h>
2 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 函数--- 文件定位

1  #include<sys/types.h>
2  #include<unistd.h>
3 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

1 #ifndef __IO_H__
2 #define __IO_H__
3 
4 extern void copy(int fdin, int fdout);
5 
6 #endif

  io.c

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include "io.h"
 6 #include <string.h>
 7 #include <errno.h>
 8 #include <stdlib.h>
 9 #include <stdio.h>
10 #include <fcntl.h>
11 
12 
13 #define BUFFER_LEN 1024
14 
15 /* 文件的读写拷贝 */
16 void copy(int fdin, int fdout)
17 {
18     char buff[BUFFER_LEN];
19     ssize_t size;
20 
21     while((size = read(fdin, buff, BUFFER_LEN)) > 0) { //从 fdin 中读取 BUFFER_LEN 个字节存放入  buff 中
22         if(write(fdout, buff, size) != size) {
23             fprintf(stderr, "write error: %s\n", strerror(errno));
24             exit(1);
25         }
26     }
27     if(size < 0) {
28         fprintf(stderr, "read error:%s\n", strerror(errno));
29         exit(1); // 相当于 return 1;
30     }
31 }

  将 io.c 编译成 .o 文件,供其他模块进行调用

1 gcc -o obj/io.o -Iinclude -c src/io.c
  • -o:指定输出的目录和文件格式
  • -Iinclude:指定包含的头文件目录,-I使指定包含头文件,后面的inlcude 即是头文件所在的目录,也可以采用绝对路径
  • -c:指定源文件

  cp.c

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include "io.h"
 6 #include <string.h>
 7 #include <errno.h>
 8 #include <stdlib.h>
 9 #include <stdio.h>
10 #include <fcntl.h>
11 
12 int main(int argc, char *argv[])
13 {
14     if(argc != 3) {
15         fprintf(stderr, "usage: %s srcfile destfile\n", argv[0]);
16         exit(1);
17     }
18 
19     int fdin;
20     int fdout;
21 
22     //打开一个待读取的文件
23     fdin = open(argv[1], O_RDONLY);
24     if(fdin < 0) {
25         fprintf(stderr, "open error: %s\n", strerror(errno));
26         exit(1);
27     } else {
28         printf("open file: %d\n", fdin);
29     }
30 
31     //打开一个待写入的文件
32     fdout = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0777);
33     if(fdout < 0) {
34         fprintf(stderr, "open error: %s\n", strerror(errno));
35         exit(1);
36     } else {
37         printf("open file: %d\n", fdout);
38     }
39 
40     //文件复制
41     copy(fdin, fdout);
42 
43     close(fdin);
44     close(fdout);
45 
46     return 0;
47 }

  编译:

1 gcc -o bin/cp -Iinclude obj/io.o src/cp.c

  运行:

  

  

  

  

3.3.2 lseek 文件定位

(1)例子1

  打印要读取的文件的总的大小

  每次写完后,文件定位的位置

  io.c

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include "io.h"
 6 #include <string.h>
 7 #include <errno.h>
 8 #include <stdlib.h>
 9 #include <stdio.h>
10 #include <fcntl.h>
11 
12 
13 #define BUFFER_LEN 1024
14 
15 /* 文件的读写拷贝 */
16 void copy(int fdin, int fdout)
17 {
18     char buff[BUFFER_LEN];
19     ssize_t size;
20 
21 //    printf("file length: %ld\n", lseek(fdin, 0L, SEEK_END));//将文件定位到文件尾部,偏移量为0L
22 //    lseek(fdin, 0L, SEEK_SET);// 定位到文件开头
23 
24     while((size = read(fdin, buff, BUFFER_LEN)) > 0) { //从 fdin 中读取 BUFFER_LEN 个字节存放入  buff 中
25         printf("current: %ld\n", lseek(fdin, 0L, SEEK_CUR));    //打印当前位置
26 
27         if(write(fdout, buff, size) != size) {
28             fprintf(stderr, "write error: %s\n", strerror(errno));
29             exit(1);
30         }
31     }
32     if(size < 0) {
33         fprintf(stderr, "read error:%s\n", strerror(errno));
34         exit(1); // 相当于 return 1;
35     }
36 }

  cp.c

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include "io.h"
 6 #include <string.h>
 7 #include <errno.h>
 8 #include <stdlib.h>
 9 #include <stdio.h>
10 #include <fcntl.h>
11 
12 int main(int argc, char *argv[])
13 {
14     if(argc != 3) {
15         fprintf(stderr, "usage: %s srcfile destfile\n", argv[0]);
16         exit(1);
17     }
18 
19     int fdin;
20     int fdout;
21     off_t ret;
22 
23     //打开一个待读取的文件
24     fdin = open(argv[1], O_RDONLY);
25     if(fdin < 0) {
26         fprintf(stderr, "open error: %s\n", strerror(errno));
27         exit(1);
28     } else {
29         printf("open file: %d\n", fdin);
30     }
31 
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     }
44 
45     //打开一个待写入的文件
46     fdout = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0777);
47     if(fdout < 0) {
48         fprintf(stderr, "open error: %s\n", strerror(errno));
49         exit(1);
50     } else {
51         printf("open file: %d\n", fdout);
52     }
53 
54     //文件复制
55     copy(fdin, fdout);
56 
57     close(fdin);
58     close(fdout);
59 
60     return 0;
61 }

  编译:

1 gcc -o bin/cp -Iinclude src/io.c src/cp.c

  执行:

  

(2)空洞文件制作

   空洞文件就是从文件尾部跳出若干个字节再写入信息,中间空出来的信息就是一个空洞

  hole_file.c

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <string.h>
 6 #include <errno.h>
 7 #include <stdlib.h>
 8 #include <stdio.h>
 9 #include <fcntl.h>
10 
11 //生成空洞文件
12 char *buff = "0123456789";
13 
14 
15 int main(int argc, char *argv[])
16 {
17     if(argc < 2) {
18         fprintf(stderr, "usage: %s [file]\n", argv[0]);
19         exit(1);
20     }
21             
22     int fd;
23     size_t size;
24 
25     fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
26     if(fd < 0) {
27         perror("open error");
28         exit(1);
29     }
30 
31     // 写入多少个字节,一个字符串占多少个字节
32     size = strlen(buff) * sizeof(char);
33     
34     // 将字符串写入到空洞文件中
35     if(write(fd, buff, size) != size) {
36         perror("write error");
37         exit(1);
38     }
39 
40     // 定位到文件尾部的 10 个字节处
41     if(lseek(fd, 10L, SEEK_END) == -1) {
42         perror("lseek error");
43         exit(1);
44     }
45 
46     // 从文件尾部的10个字节处再写入字符串
47     if(write(fd, buff, size) != size) {
48          perror("write error");
49          exit(1);
50     }
51 
52     close(fd);
53     return 0;
54     
55 }

  编译:

1 gcc -o bin/hole_file src/hole_file.c

  执行:

  

posted @ 2018-05-13 15:20  游戏进行中  阅读(419)  评论(0编辑  收藏  举报