我有一组相当大的文件(每个文件大约50兆字节,至少100个),但我需要在每个文件中插入一个小标题(大约两打行)以进行处理。我希望编写一个bash或python脚本来完成此任务,但我找不到一个常数时间函数,让我能够在文本文件前面插入内容。如果它不是常数时间,我认为完成该任务将需要太长的时间。有没有人对这个问题有经验?
我有一组相当大的文件(每个文件大约50兆字节,至少100个),但我需要在每个文件中插入一个小标题(大约两打行)以进行处理。我希望编写一个bash或python脚本来完成此任务,但我找不到一个常数时间函数,让我能够在文本文件前面插入内容。如果它不是常数时间,我认为完成该任务将需要太长的时间。有没有人对这个问题有经验?
mkfifo(1)
来伪造一个文件名。
例如,在bash
中...
echo 'My header' > header.txt
echo 'My content' > content.txt
mkfifo fakefile.txt
cat header.txt content.txt > fakefile.txt &
cat fakefile.txt
...会流式传输这两个文件的内容,而不是创建一个新文件。
在Unix文件中,无论是在开头还是中间,都无法以恒定时间插入文本。另一方面,根据您的处理方式,有一小部分可能可以完全避免插入。如果您的处理工具能够从管道读取,则可以这样做:
然后你可以执行如下操作:
cat headerfile datafile | myprocessingtool
因此,数据文件实际上并未被修改。
我认为这是你能做到的最好的(bash):
MYHEADER=/path/to/the/header
HEADERSIZE=$(stat --format %s "$MYHEADER")
for FILENAME in $FILES; do
OLDSIZE=$(stat --format %s "$FILENAME")
cat "$MYHEADER" "$FILENAME" > /tmp/headerize.tmp
NEWSIZE=$(stat --format %s /tmp/headerize.tmp)
EXPECTEDSIZE=$(($HEADERSIZE+$OLDSIZE))
if [ "$NEWSIZE" -eq "$EXPECTEDSIZE" ]; then
mv /tmp/headerize.tmp "$FILENAME"
else
echo "Something odd happened when processing $FILENAME, headerization skipped for this file."
fi
done
除非你的系统极度糟糕,或者对时间限制要求过高,否则这个过程应该在合理的时间内完成。并且包括错误检查。
当然,你应该确保你的头文件以换行符结束,否则最终的头文件行和第一行文本文件将被合并。
这里唯一剩下的优化就是确保临时文件写入与原始文件相同的文件系统;这可能会加快mv命令的速度。
总的来说,内容插入都很慢。无论是在内存中还是在磁盘上都是如此。我相信你永远不可能找到一个常数时间解决方案。但是,对于一次性批处理作业,你可能实际上并不需要一个。
这是我认为你可以在Python中实现的最快速度。由于它不创建临时文件,因此可能比bash版本更快:
MYHEADERPATH=/path/to/the/header
with open(MYHEADERPATH, 'r') as f:
header = f.read()
for filename in files:
with open(filename, 'r') as f:
content = f.read()
with open(filename, 'w') as f:
f.write(header + content)
然而,如果你希望它绝对安全,你就必须像bash脚本一样去做,所以最终速度可能会有一些差异。
OLDSIZE
/NEWSIZE
检查似乎是不必要的;在Python版本中你没有做类似的事情。使用临时文件并重命名与覆盖现有文件之间在性能上没有(有意义的)差异。 - chepner/tmp
通常位于自己的文件系统中。在Arch Linux上肯定是这样)。我故意使版本不同,因为这个原因。此外,cat命令可能会失败(空间不足),您不希望用截断的版本覆盖它。 - kampu