• 三、文件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
    ", strerror(errno));
    24             exit(1);
    25         }
    26     }
    27     if(size < 0) {
    28         fprintf(stderr, "read error:%s
    ", 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
    ", 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
    ", strerror(errno));
    26         exit(1);
    27     } else {
    28         printf("open file: %d
    ", 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
    ", strerror(errno));
    35         exit(1);
    36     } else {
    37         printf("open file: %d
    ", 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
    ", 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
    ", lseek(fdin, 0L, SEEK_CUR));    //打印当前位置
    26 
    27         if(write(fdout, buff, size) != size) {
    28             fprintf(stderr, "write error: %s
    ", strerror(errno));
    29             exit(1);
    30         }
    31     }
    32     if(size < 0) {
    33         fprintf(stderr, "read error:%s
    ", 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
    ", 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
    ", strerror(errno));
    27         exit(1);
    28     } else {
    29         printf("open file: %d
    ", fdin);
    30     }
    31 
    32     ret = lseek(fdin, 0L, SEEK_END); //将文件定位到文件末尾
    33     if(ret == -1) {
    34         fprintf(stderr, "lseek error: %s
    ", strerror(errno));
    35         exit(1);
    36     }
    37     printf("file length: %ld
    ", ret);
    38 
    39     ret = lseek(fdin, 0L, SEEK_SET);// 定位到文件开头
    40     if(ret == -1) {
    41         fprintf(stderr, "lseek error: %s
    ", 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
    ", strerror(errno));
    49         exit(1);
    50     } else {
    51         printf("open file: %d
    ", 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]
    ", 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

      执行:

      

  • 相关阅读:
    Spring中的@Transactional(rollbackFor = Exception.class)属性详解
    查询数据库中表数量和各表中数据量
    69道Spring面试题和答案
    Spring常见面试题总结(超详细回答)
    nginx 解决session一致性
    redis 主从同步
    如何实现一个线程安全的单例,前提是不能加锁
    InnoDB中一棵B+树能存多少行数据
    ConcurrentHashMap 源码分析
    java HashMap 源码解析
  • 原文地址:https://www.cnblogs.com/kele-dad/p/9022312.html
Copyright © 2020-2023  润新知