复制一个空洞文件且忽略掉其空洞内容

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

 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>\n",argv[0]);
18     exit(EXIT_FAILURE);
19     }
20     if(-1 == (fd=open(argv[1],MODE,0644)))
21     {
22     printf("%s[open]%s\n",argv[0],strerror(errno));
23     exit(EXIT_FAILURE);
24     }
25     if(-1 == write(fd,"abcde",5))
26     {
27     printf("%s[write]%s\n",argv[0],strerror(errno));
28     exit(EXIT_FAILURE);
29     }
30     if(-1 == lseek(fd,5,SEEK_END))
31     {
32     printf("%s[lseek]%s\n",argv[0],strerror(errno));
33     exit(EXIT_FAILURE);
34     }
35     if(-1 == write(fd,"ABCDE",5))
36     {
37     printf("%s[write]%s\n",argv[0],strerror(errno));
38     exit(EXIT_FAILURE);
39     }
40     if(-1 == close(fd))
41     {
42     printf("%s[close]%s\n",argv[0],strerror(errno));
43     exit(EXIT_FAILURE);
44     }
45     printf("空洞文件已经创建成功!\n");
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\n",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\n",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\n",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\n",argv[0]+2,strerror(errno));
          exit(EXIT_FAILURE);
      }
    }
    if(-1 == close(fd_s))
    {
      printf("%s[close]%s\n",argv[1]+2,strerror(errno));
      exit(EXIT_FAILURE);
    }
    if(-1 == close(fd_d))
    {
      printf("%s[close]%s\n",argv[2]+2,strerror(errno));
      exit(EXIT_FAILURE);
    }

    return 0;
}

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

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

  

时间: 2024-11-06 12:18:29

复制一个空洞文件且忽略掉其空洞内容的相关文章

C# 复制一个Word文档的部分或全部内容到另一个Word文档

C# 复制一个Word文档的部分或全部内容到另一个Word文档 我最近喜欢折腾Office软件相关的东西,想把很多Office软件提供的功能用.NET来实现,如果后期能把它用来开发一点我自己的小应用程序那就更好了. 扯远了,回到正题.复制文档内容这个功能太常见啦,在微软Word中实现这个功能很简单,只需要复制和粘贴就行了.这篇文章的主要目的是记录如何用C#来实现复制一个Word文档的部分或全部内容到另一个word文档,废话不多说,下面开始. 第一部分:复制部分内容: 在我的这个示例中,复制部分内

[19/04/04-星期四] IO技术_CommonsIO(通用IO,别人造的轮子,FileUtils类 操作文件 &amp; IOUtilsl类 操作里边的内容 )

一.概念 JDK中提供的文件操作相关的类,但是功能都非常基础,进行复杂操作时需要做大量编程工作.实际开发中,往往需要 你自己动手编写相关的代码,尤其在遍历目录文件时,经常用到递归,非常繁琐. Apache-commons工具包中提供了IOUtils/FileUtils,可以让我们非常方便的对文件和目录进行操作. Apache软件基金会(也就是Apache Software Foundation,简称为ASF),是专门为支持开源软件项目而办的一个非盈利性组织. 在它所支持的Apache项目与子项目

复制一个文件

package bianchengti; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /* * 复制一个文件 */ public class FileCopy { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub Fi

使用Git如何优雅的忽略掉一些不必的文件

熟悉使用Git之后发现,使用sourceTree来管理和开发项目会变得更高效,现在我用bitbucket管理自己的项目,它提供了私有的仓库,用起来还是比较爽,不过刚开始用的时候,只要一打开本地仓库的工程,就会修改一个缓冲文件,然后在sourceTree很不智能的提示项目改动,无奈右键ignore文件,但是后来发现这样太不优雅了,每次工程都要右键N多个文件,寻思着一定会有优雅的方式解决..于是各种折腾...最后找到解决办法了. 第一步要找到一个 .gitignore_global 的配置文件,在~

git忽略掉文件或文件夹

在工程根目录下建一个.gitignore文件文件,文件内容如下: target/ *.log 参考链接: git如何忽略文件或者文件夹 Git 忽略一些文件不加入版本控制

git忽略掉文件权限检查

有时 git diff 执行显示文件内容没变化,但是有 old mode xxx new mode,原因是文件的权限,被chmod变化了,这种变化也被 diff 识别出来了,让git忽略掉文件权限检查可以使用一下命令: git config core.fileMode false 原文地址:https://www.cnblogs.com/senlinyang/p/8435928.html

使用字节流复制一个文件夹

package com.tanlei.Demo; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /* * 使用字节流复制一个文件夹 */ public class CopyDirDemo { public static void main(S

一键帮你复制多个文件到多个机器——PowerShell小脚本(内附PS远程执行命令问题解析)

作为一个后台程序猿,经常需要把一堆程序集(DLL)或者应用程序(EXE)复制到多个服务器上,实现程序的代码逻辑更新,用以测试新的功能或改动逻辑.这里给大家介绍一个自己实现的PowerShell脚本,方便大家替换DLL或者EXE到多个Windows机器上. 一.   脚本用途 用于方便复制多个文件到多个服务器上. 二.   脚本功能 脚本的主要功能如下: 支持通过最后修改时间过滤文件,设定时间之前的文件不进行复制操作(逻辑设计源于Rebuild代码后只替换新Build出来的有改动的文件): 支持多

C#中用ILMerge将所有引用的DLL打成一个DLL文件

C#中用ILMerge将所有引用的DLL打成一个DLL文件 有些文件是必须一起使用的,如果能把多个DLL打包成一个DLL文件,那么引用文件的时候就不需要一个个地去引用,而且每次移动文件的时候也不至于少了哪个必须的DLL文件. 多个DLL文件打包成一个DLL文件的方法如下:1.先到下面的网址下载ILMerge安装 http://www.microsoft.com/en-us/download/details.aspx?id=17630 2.安装完之后,执行cmd命令,进入ILMerge目录, 把t