【问题标题】:Constant time text file modification恒定时间文本文件修改
【发布时间】:2013-05-15 02:44:19
【问题描述】:

我有一组相当大的文件(每个大约 50 兆字节,至少有一百个),但我需要在每个文件上插入一个小标题(大约 2 打行)以进行处理。我希望在 bash 或 python 中编写一个脚本来执行此操作,但我找不到可以让我在文本文件前面插入的恒定时间函数。如果不是固定时间,我认为完成时间会太长。有没有人遇到过这个问题?

【问题讨论】:

  • 不,不是固定时间。您不能在不重写整个文件的情况下将数据添加到文件中。这是文件系统的基本限制,而不是编程语言。
  • ...但是如果您以后打算open() Python(或其他语言)中的文件来“处理”它们,您可以伪造一个类似文件的对象来“假装”它们在它们前面加上“小标题”,而不是修改实际文件,假设这是一个可接受的替代方案。

标签: python bash


【解决方案1】:

与 Uwe 的回答类似,但如果您的处理工具只能接受参数作为文件名,您可以使用 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

...将流式传输两个文件的内容,而不是创建一个新文件。

【讨论】:

    【解决方案2】:

    我相信这已经接近你将要做的最好的事情了(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 命令的速度。

    一般来说,内容插入很慢。无论是在内存中还是在磁盘上,都是如此。我相信您将永远找不到恒定时间解决方案。但是,您可能实际上并不需要一个用于一次性批处理作业。

    这是 IMO 在 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 : True IFF 临时文件在同一个文件系统上(/tmp 通常在它自己的文件系统中。它当然在这里,在 Arch Linux 上)。因此,我故意使版本不同。此外,cat 命令可能会失败(空间不足),并且您不想用截断的版本覆盖。
    • @chepner:我开始考虑这个问题,并得出结论,如果不让 python 版本模仿 bash 版本,我唯一的办法就是 df,这对于这么小的脚本来说太荒谬了 :) 并且bash 脚本并不完全安全:可能会发生部分截断(其中 n_truncated_bytes
    【解决方案3】:

    您不能在恒定时间内将文本插入 Unix 文件,无论是在开头还是中间。另一方面,根据您考虑的处理,您可以完全避免插入的可能性很小。 如果你的处理工具能够从管道中读取数据,它就可以工作。然后你可以做类似的事情

    cat headerfile datafile | myprocessingtool
    

    这样数据文件就不会被实际修改。

    【讨论】:

    • 为了澄清,当我说恒定时间时,我的意思是相对于修改文件的恒定时间。显然,它必须与插入的文本成线性关系。还是不行吗?
    • @user2401982 附加到文件时,所花费的时间(至少在理论上)与您要附加的新数据的大小成正比,但如果您要预先或插入,它是成正比的为原始文件和新数据的大小之和。
    猜你喜欢
    • 2011-08-16
    • 1970-01-01
    • 2014-03-11
    • 2011-01-15
    • 2010-09-09
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 2017-03-30
    相关资源
    最近更新 更多