我处理非常大的二进制文件(每个文件几 GB 到多个 TB)。这些文件以旧格式存在,升级需要将标题写入文件的前面。我可以创建一个新文件并重写数据,但有时这可能需要很长时间。我想知道是否有更快的方法来完成此升级。该平台仅限于 Linux,我愿意使用低级函数(ASM、C、C++)/文件系统技巧来实现这一点。主要库是 Java,JNI 是完全可以接受的。
5 回答
在本地没有通用的方法来做到这一点。
也许某些文件系统提供了一些功能来执行此操作(无法给出任何提示),但是您的代码将依赖于文件系统。
一个解决方案可能是模拟文件系统:您可以将数据存储在一组多个文件中,然后提供一些函数来打开、读取和写入数据,就好像它是一个文件一样。
听起来很疯狂,但是如果可以更改从文件读取数据的功能,您可以按相反的顺序存储文件数据。在这种情况下,您可以在文件末尾附加数据(以相反的顺序)。这只是一个普遍的想法,所以我不能推荐任何特别的东西。反转当前文件的代码如下所示:
std::string records;
ofstream out;
std::copy( records.rbegin(), records.rend(), std::ostream_iterator<string>(out));
这取决于您所说的“文件系统技巧”是什么意思。如果您愿意使用文件系统的磁盘格式,并且要添加的标头大小是文件系统块大小的倍数,那么您可以编写一个程序来直接操作文件系统的磁盘结构(卸载文件系统)。
不过,这家企业就像听起来一样多毛——如果你有数百个这样的巨型文件要处理,这可能才值得。
我只会使用标准的 Linux 工具来完成它。
编写另一个应用程序来做这件事似乎不是最理想的。
cat headerFile oldFile > tmpFile && mv tmpFile oldFile
我知道这是一个老问题,但我希望这对未来的人有所帮助。与模拟文件系统类似,您可以简单地使用命名管道:
mkfifo /path/to/file_to_be_read
{ echo "HEADER"; cat /path/to/source_file; } > /path/to/file_to_be_read
然后,您针对 运行旧程序/path/to/file_to_be_read
,输入将是:
HEADER
contents of /path/to/source_file
...
只要程序按顺序读取文件并且不执行mmap()
或rewind()
超过缓冲区,这将起作用。