在python中编辑文件

时间:2009-03-09 15:12:30

标签: python svn

我写了一个小python程序作为个人实用程序来帮助我进行一些重构。它类似于unix替换,除了它支持正则表达式并对目录中的所有文件和(可选)所有子目录进行操作。

问题是我没有替换到位。我正在打开文件,将内容传递到内存中,然后覆盖文件,如下所示:

file = open('path/to/file','r')
in_string = file.read()
file.close()
# ...
#Processing logic
# ...
file = open('path/to/file','w')
file.write(out_string)
file.close()

除了显而易见的性能/内存问题,这是合法的,但对我的使用不是一个问题,这个方法还有另一个缺点。 SVN吓坏了。事后我可以做一些复制和粘贴解决方法来修复svn在提交时抛出的校验和错误,但它使得实用程序毫无意义。

有更好的方法吗?我猜测如果我正在编辑文件就不存在任何问题。我该怎么做?

6 个答案:

答案 0 :(得分:8)

我怀疑问题是你实际上编辑了错误的文件。当您只是修改跟踪文件时,Subversion不应该引发任何关于校验和的错误 - 与 修改它们的方式无关。

也许您不小心编辑了.svn目录中的文件?在.svn/text-base中,Subversion使用相同的名称和扩展名.svn-base存储文件的副本,请确保您没有编辑这些副本!

答案 1 :(得分:2)

“SVN吓坏了”是什么意思?

无论如何,vi / emacs / etc的工作方式如下:

f = open("/path/to/.file.tmp", "w")
f.write(out_string)
f.close()
os.rename("/path/to/.file.tmp", "/path/to/file")

(好吧,那里实际上有一个“fsync”......但是我不知道如何在Python中做到这一点)

它执行该复制的原因是为了确保,如果系统在写入新文件的一半时间死亡,旧的文件仍然存在...并且'重命名'操作被定义为原子,因此它将要么工作(你获得新文件的100%)或不工作(你得到100%的旧文件) - 你永远不会留下半文件。

答案 2 :(得分:1)

也许fileinput模块可以使您的代码更简单/更短:

以下是一个例子:

import fileinput

for line in fileinput.input("test.txt", inplace=1):
    print "%d: %s" % (fileinput.filelineno(), line),

答案 3 :(得分:0)

吓坏了怎么样?您所描述的内容,如果它正在运行, “就地”编辑文件,至少与 vi(1)一样。

答案 4 :(得分:0)

尝试'file = open('path / to / file','w +')'。这意味着您正在更新现有文件,而不是编写新文件。

答案 5 :(得分:0)

我怀疑Ferdinand's answer,你正在递归.svn目录,解释你为什么要搞乱SVN,但请注意你处理文件的方式还有另一个缺陷。

如果您的程序被终止,或者您的计算机在错误的位置崩溃(当您写出更改的内容时),则可能会丢失文件的原始内容和新内容。更强大的方法是执行以下步骤:

  1. 将文件读入内存,然后执行翻译
  2. 将新内容写入“filename.new”,而不是原始文件名。
  3. 删除原始文件,并将“filename.new”重命名为“filename”
  4. 这样,如果在错误的位置被杀,您将不会有丢失数据的风险。请注意,fileinput模块将为您处理大部分内容。可以给出一系列要处理的文件,如果指定inplace = True,则会将stdout重定向到相应的文件(保留备份)。然后,您可以将代码构造为:

    import os
    import fileinput
    
    def allfiles(dir, ignore_dirs=set(['.svn'])):
        """Generator yielding all writable filenames below dir.
        Ignores directories specified 
        """
        for basedir, dirs, files in os.walk(dir):
            if basedir in ignore_dirs:
                dirs[:]=[] # Don't recurse
                continue  # Skip this directory
    
            for filename in files:
                filename = os.path.join(basedir, filename)
                # Check the file is writable
                if os.access(filename, os.W_OK):
                    yield filename
    
    
    for line in fileinput.input(allfiles(PATH_TO_PROCESS), inplace=True):
        line = perform_some_substitution(line)
        print line.rstrip("\n") # Print adds a newline, but line already has one