zoukankan      html  css  js  c++  java
  • 三、文件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

      执行:

      

  • 相关阅读:
    使用 Dockerfile 定制镜像
    UVA 10298 Power Strings 字符串的幂(KMP,最小循环节)
    UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)
    LeetCode Best Time to Buy and Sell Stock 买卖股票的最佳时机 (DP)
    LeetCode Number of Islands 岛的数量(DFS,BFS)
    LeetCode Triangle 三角形(最短路)
    LeetCode Swap Nodes in Pairs 交换结点对(单链表)
    LeetCode Find Minimum in Rotated Sorted Array 旋转序列找最小值(二分查找)
    HDU 5312 Sequence (规律题)
    LeetCode Letter Combinations of a Phone Number 电话号码组合
  • 原文地址:https://www.cnblogs.com/kele-dad/p/9022312.html
Copyright © 2011-2022 走看看