Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python中的文件编辑_Python_Svn - Fatal编程技术网

python中的文件编辑

python中的文件编辑,python,svn,Python,Svn,我写了一个小python程序作为个人工具来帮助我进行一些重构。它与unix replace类似,只是它支持正则表达式,并对目录和(可选)所有子目录中的所有文件进行操作 问题是我没有替换到位。我打开文件,将内容传递到内存,然后覆盖文件,如下所示: file = open('path/to/file','r') in_string = file.read() file.close() # ... #Processing logic # ... file = open('path/to/file','

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

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

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在提交时抛出的校验和错误,但这会使实用程序变得毫无意义


有更好的方法吗?我猜,如果我在原地编辑文件,就不会有任何问题。我该怎么做呢?

我该怎么做?你所描述的,如果它工作的话,就是“就地”编辑文件,至少和vi(1)一样多。

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

我怀疑问题在于您实际上编辑了错误的文件。当您只是修改跟踪文件时,Subversion不应该在校验和方面产生任何错误——不管您是如何修改它们的

可能是您无意中编辑了
.svn
目录中的文件?在
.svn/text base
中,Subversion使用相同的名称和扩展名
.svn base
存储文件副本,请确保您没有编辑这些文件

你说的“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%)——永远不会留下半个文件。

也许
文件输入
模块可以使代码更简单/更短:

下面是一个例子:

import fileinput

for line in fileinput.input("test.txt", inplace=1):
    print "%d: %s" % (fileinput.filelineno(), line),
我猜想,您正在递归到.svn目录中,这解释了为什么会弄乱svn,但请注意,在处理文件的方式中还有另一个缺陷

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

  • 将文件读入内存,然后执行翻译
  • 将新内容写入“filename.new”,而不是原始文件名
  • 删除原始文件,并将“filename.new”重命名为“filename”
  • 这样,如果在错误的点被杀死,您就不会有丢失数据的风险。请注意,该模块将为您处理其中的大部分内容。可以给它一系列要处理的文件,如果指定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
    

    这几乎肯定是问题所在。我在SVN WC中递归使用sed有过这样的经验。如果OP决定接受这个答案(或类似的答案),也许问题的标题应该重新命名,以便将来的人员搜索可能会发现它与这个问题有关?还要注意,OP的工具应该尊重只读标志。.svn中的文件是只读的。fileinput还有其他用途。。。但这不是最好的使用方法<代码>用于文件中的行(“test.txt”):打印“行:”,行更好。谢谢!我最终实现了类似的东西,但是使用了用于ignore_dirs的正则表达式。walk()列出相对于原始调用路径的所有BaseDir,这意味着所有文件('.')都不会跳过'/.svn'或'/.subdir/.svn'。现在很高兴了解fileinput!