用0重写文件。我究竟做错了什么?

时间:2017-12-09 20:43:02

标签: c++ file boost filesystems

我想用0重写文件。它只写几个字节。

我的代码:

int fileSize = boost::filesystem::file_size(filePath);

int zeros[fileSize] = { 0 };

boost::filesystem::path rewriteFilePath{filePath};
boost::filesystem::ofstream rewriteFile{rewriteFilePath, std::ios::trunc};
rewriteFile << zeros;

另外......这足以粉碎文件吗?接下来我该怎么办才能使文件无法恢复?

编辑:好的。我重写了我的代码。这段代码可以这样做吗?

int fileSize = boost::filesystem::file_size(filePath);

boost::filesystem::path rewriteFilePath{filePath};
boost::filesystem::ofstream rewriteFile{rewriteFilePath, std::ios::trunc};

for(int i = 0; i < fileSize; i++) {
    rewriteFile << 0;
}

3 个答案:

答案 0 :(得分:3)

您的代码存在一些问题。

  1. int zeros[fileSize] = { 0 };

    您正在创建一个大小为sizeof(int) * fileSize个字节的数组。对于您正在尝试的内容,您需要一个大小为fileSize字节的数组。因此,您需要使用1字节数据类型,例如(unsigned) charuint8_t

    但是,更重要的是,由于fileSize的值直到运行时才知道,因此这种类型的数组称为&#34;可变长度数组&#34; (VLA),这是C ++中的非标准功能。如果需要动态分配的数组,请使用std::vector

  2. boost::filesystem::ofstream rewriteFile{rewriteFilePath, std::ios::trunc};

    trunc标志将现有文件的大小截断为0.需要的是更新文件的元数据以重置其跟踪的字节大小,并标记所有文件&#39;使用的磁盘扇区可供重用。存储在这些扇区中的实际文件字节直到被覆盖时才被消除,因为扇区随着时间的推移而被重用。但是,您随后写入截断文件的任何字节都不能保证(并且可能不会)覆盖磁盘上的旧字节。所以,不要截断文件。

  3. rewriteFile << zeros;

    ofstream没有operator<<作为输入int[],甚至是int*。但它确实有一个operator<<,它以void*为输入(输出指向的内存地址的值)。数组衰减为指向第一个元素的指针,void*接受任何指针。这就是为什么只写几个字节的原因。您需要使用ofstream::write()来将数组写入文件,并确保使用binary标志打开该文件。

  4. 请改为尝试:

    int fileSize = boost::filesystem::file_size(filePath);
    
    std::vector<char> zeros(fileSize, 0);
    
    boost::filesystem::path rewriteFilePath(filePath);
    boost::filesystem::ofstream rewriteFile(rewriteFilePath, std::ios::binary);
    rewriteFile.write(zeros.data()/*&zeros[0]*/, fileSize);
    

    话虽这么说,你根本不需要动态分配的数组,更不用说分配给文件的完整大小的数组了。这只是浪费堆内存,特别是对于大文件。你可以这样做:

    int fileSize = boost::filesystem::file_size(filePath);
    
    const char zeros[1024] = {0}; // adjust size as desired...
    
    boost::filesystem::path rewriteFilePath(filePath);
    boost::filesystem::ofstream rewriteFile(rewriteFilePath, std::ios::binary);
    
    int loops = fileSize / sizeof(zeros);
    for(int i = 0; i < loops; ++i) {
        rewriteFile.write(zeros, sizeof(zeros));
    }
    rewriteFile.write(zeros, fileSize % sizeof(zeros));
    

    或者,如果您打开文件的内存映射视图(Windows上的MapViewOfFile(),Linux上的mmap()等),那么您只需使用std::copy()或{{1}直接将整个文件的字节清零,而不使用任何数组。

      

    另外......这足以粉碎文件吗?

    不是,不。在物理硬件层,用零覆盖文件一次仍然可以在磁盘扇区中留下残余信号,可以用足够的工具恢复 。您应该使用不同类型的随机数据多次覆盖该文件,而不仅仅是零。这将更彻底地扰乱各个部门的信号。

答案 1 :(得分:0)

只是为了好玩,用随机数据覆盖:

<强> Mathias R. Jessen's helpful answer

#include <boost/iostreams/device/mapped_file.hpp>
#include <random>
namespace bio = boost::iostreams;

int main() {
    bio::mapped_file dst("main.cpp");

    std::mt19937 rng { std::random_device{} () };
    std::uniform_int_distribution<char> dist;

    std::generate_n(dst.data(), dst.size(), [&] { return dist(rng); });
}

请注意,它在编译后对自己的源文件进行加扰:)

答案 2 :(得分:0)

我不能强烈强调覆盖文件内容的注释的重要性并不能保证任何原始数据都被覆盖。因此,对此问题的所有其他答复均不适用于任何最新的操作系统。

现代文件系统是基于范围的,这意味着文件存储为已分配块的链接列表。更新块可能更快,文件系统可以编写一个全新的块并简单地调整链表,这就是他们所做的。实际上,写时复制文件系统始终写入任何已修改块的副本,并更新其当前有效范围的B树。

此外,即使您的文件系统没有这样做,您的硬盘驱动器也可能使用完全相同的技术来提高性能,并且由于闪存的工作原理,任何SSD几乎肯定都会使用这种技术。因此,覆盖数据以“擦除”它在现代系统中毫无意义。无法做到。保持旧数据隐藏的唯一安全方法是全盘加密。你还在欺骗自己和用户的任何其他事情。