zoukankan      html  css  js  c++  java
  • 复制一个空洞文件且忽略掉其空洞内容

      首先说一下什么叫做空洞文件!比如说,下面这段代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 #include<errno.h>
     5 #include<sys/types.h>
     6 #include<sys/stat.h>
     7 #include<fcntl.h>
     8 #include<unistd.h>
     9 
    10 #define MODE O_CREAT|O_RDWR|O_TRUNC
    11 int main(int argc,char *argv[])
    12 {
    13     int fd;
    14 
    15     if(argc != 2)
    16     {
    17     printf("Usage:%s <filename>
    ",argv[0]);
    18     exit(EXIT_FAILURE);
    19     }
    20     if(-1 == (fd=open(argv[1],MODE,0644)))
    21     {
    22     printf("%s[open]%s
    ",argv[0],strerror(errno));
    23     exit(EXIT_FAILURE);
    24     }
    25     if(-1 == write(fd,"abcde",5))
    26     {
    27     printf("%s[write]%s
    ",argv[0],strerror(errno));
    28     exit(EXIT_FAILURE);
    29     }
    30     if(-1 == lseek(fd,5,SEEK_END))
    31     {
    32     printf("%s[lseek]%s
    ",argv[0],strerror(errno));
    33     exit(EXIT_FAILURE);
    34     }
    35     if(-1 == write(fd,"ABCDE",5))
    36     {
    37     printf("%s[write]%s
    ",argv[0],strerror(errno));
    38     exit(EXIT_FAILURE);
    39     }
    40     if(-1 == close(fd))
    41     {
    42     printf("%s[close]%s
    ",argv[0],strerror(errno));
    43     exit(EXIT_FAILURE);
    44     }
    45     printf("空洞文件已经创建成功!
    ");
    46     return 0;
    47 }

     在这段代码中,我首先在文件中写入abcde五个字节的内容,然后在把文件指针从文件尾端向后移动5个字节,再写入ABCDE5个字节的内容!这样在这个文件中,两次abcde中间就会产生一个5个字节空洞,这个空洞的内容都被写成了0。文件的空洞并不要求在磁盘上占用存储区,具体的处理方式和文件系统的实现有关!我这个文件如果用vim打开的话会是这样的效果!

    中间蓝色的^@就表示内容为0的空洞!

      接下来,我们再来谈一谈如何来复制一个空洞文件,并且让忽略掉它的空洞部分的内容!这里我们就利用了空洞内容为0的这个特性!具体的实现方法就是通过查看读出来的文件内容的值是否为0,如果是则忽略,否则就存储起来!具体的实现代码如下:

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<errno.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<unistd.h>
    #define MODE O_RDWR
    #define SIZE 4096
    int main(int argc,char *argv[])
    {
        if(argc != 3)
        {
        printf("Usage: %s source_file destination_file
    ",argv[0]);
        exit(EXIT_FAILURE);
        }
    
        int fd_s,fd_d;
        //分别用来存储读出和写入的文件内容
        char buf_r[SIZE],buf_w[SIZE];
        //写入缓存指针的计数器
        int w_l;    //read_length,write_length
        //读出和写入的长度
        int r_len,w_len;
    
        if(-1 == (fd_s=open(argv[1],MODE)))
        {
          printf("%s[open]%s
    ",argv[1],strerror(errno));
          exit(EXIT_FAILURE);
        }
        if(-1 == (fd_d=open(argv[2],MODE|O_CREAT|O_TRUNC,0644)))    //如果目标文件已经存在,则将其截短成0
        {
          printf("%s[open]%s
    ",argv[2],strerror(errno));
          exit(EXIT_FAILURE);
        }
        //如果文件的内容过于庞大,我这里是分批存储的!且在《Unix环境高级编程》的3.9节已经论证过当SIZE为4096的时候I/O的效率最佳!
        while((r_len=read(fd_s,buf_r,SIZE)) > 0)
        {
          w_l=0;
          //将读出内容中的非空洞内容赋值到buf_w中
          for(int i=0;i<r_len;i++)
          {
              if(buf_r[i] != 0)
              buf_w[w_l++]=buf_r[i];
          }
          //这里得到的w_l表示的是字符数组的长度,注意数组是从0开始的
          if(-1 == (w_len=write(fd_d,buf_w,w_l)))
          {
              printf("%s[write]%s
    ",argv[0]+2,strerror(errno));
              exit(EXIT_FAILURE);
          }
        }
        if(-1 == close(fd_s))
        {
          printf("%s[close]%s
    ",argv[1]+2,strerror(errno));
          exit(EXIT_FAILURE);
        }
        if(-1 == close(fd_d))
        {
          printf("%s[close]%s
    ",argv[2]+2,strerror(errno));
          exit(EXIT_FAILURE);
        }
    
        return 0;
    }

      上面那个程序的思路就是每次读取4096字节,分批读取源文件的内容到buf_r中,然后检查buf_r的内容,如果是0则忽略,否则就暂存到buf_w中,然后将其写入到目标文件中!

    检验这个程序的运行结果我用了一个较大的空洞文件,具体的运行结果如下图:

      

  • 相关阅读:
    curl命令常见用法汇总 good
    Spring Boot flyway的启动时机比较早
    android 签名被篡改(Keystore was tampered with, or password was incorrect)
    android sdk 如何重新生成debug.keystore
    Android的debug.keystore拒绝访问导致的生成异常及解决方案
    Android生成keystore是报错拒绝访问
    android 高德地图出现【定位失败key鉴权失败】
    Android Studio开发入门-引用jar及so文件
    android 自定义AlertDialog(一段)
    Android自定义控件之日历控件
  • 原文地址:https://www.cnblogs.com/bwangel23/p/4112364.html
Copyright © 2011-2022 走看看