文本头部没有发生文本

时间:2013-01-09 01:59:30

标签: python

我有下面的代码做除了我想要的一切:-)。目标很简单,我试图在目录(和子目录)中存在的每个文件的顶部添加appendtext变量中的文本,脚本运行正常但是文字没有附加......我哪里错了?

import os
import sys
import fnmatch
temp_fname = "temp_file"

appendtext="""Test string
"""
if len(sys.argv) < 2:
    sys.exit('Usage: test.py <build directory>')

for path,dirs,files in os.walk(sys.argv[1]):
    for fname in files:
        for pat in ['*.*']:
            if fnmatch.fnmatch(fname,pat):
                fullname = os.path.join(path,fname)
                with open(fullname, "r") as in_file:
                    with open(temp_fname, "w") as out_file:
                        out_file.write(appendtext)
                        for line in in_file:
                            out_file.write(line)
                os.rename(temp_fname, fullname)

2 个答案:

答案 0 :(得分:2)

如果您希望文本顶部的文本,您应该这样做:

temp_fname = "temp_file"
# the next line doesn't work in Python 2.5, 2.6, or 3.0
with open(fullname, "r") as in_file, open(temp_fname, "w") as out_file:
    out_file.write(appendtext)
    for line in in_file:
        out_file.write(line)
os.rename(temp_fname, fullname)

以上是Python 2.6重写的内容:

temp_fname = "temp_file"
with open(temp_fname, "w") as out_file:
    with open(fullname, "r") as in_file:
        out_file.write(appendtext)
        for line in in_file:
            out_file.write(line)
os.rename(temp_fname, fullname)

我们可以比这更好一些。这始终使用相同的临时文件名("temp_file"),并且该文件将始终在单个目录中创建(运行此目录时为默认目录)。我们真正想要的是一个临时文件,它具有唯一的名称,创建在与我们将要编辑的文件完全相同的目录中。 Python为我们提供了一个名为tempfile的方便模块,用于创建临时文件。

默认情况下,您只是获得一个打开的文件句柄而您不知道文件名。但我们需要知道文件名,以便在完成临时复制后,我们可以将其重命名为原始文件名。 tempfile为此类案件提供了NamedTemporaryFile

这是一个完整的程序:

import fnmatch
import os
import sys
import tempfile

headertext = "# header text\n\n"

def want_this_file(fname):
    for pat in ['*']:
        if fnmatch.fnmatch(fname, pat):
            return True
    return False

def prepend_file(fullname, path):
    # with statement means temp file is written and closed at end of with
    with tempfile.NamedTemporaryFile(dir=path, delete=False) as out_file:
        with open(fullname, "r") as in_file:
                out_file.write(headertext)
                for line in in_file:
                    out_file.write(line)
        # before temp file is closed, get its name
        temp_fname = out_file.name
    # rename temp file to fullname, clobbering original
    os.rename(temp_fname, fullname)


start_directory = sys.argv[1]

for dirpath, dirnames, filenames in os.walk(start_directory):
    for fname in filenames:
        if want_this_file(fname):
            fullname = os.path.join(dirpath, fname)
            prepend_file(fullname, dirpath)

此答案使用“编写临时文件,然后将临时文件重命名为原始名称”模式。这是你应该这样做的方式。它允许代码编写新版本,并且只有在新版本完全成功编写时,然后执行单个操作才能将新文件重命名为旧文件名。因此,如果在尝试编写新版本时出现任何问题,原始文件保持不变。这是解决问题的安全方法。

我们希望在与原始文件相同的目录中创建临时文件,这样os.rename()操作将非常便宜。在Linux系统上,系统临时目录(/tmp)可能位于其自己的分区上,如果您只是让tempfile在其中创建临时文件,则重命名操作可能涉及再次复制数据!如果临时文件位于同一目录中,则重命名操作始终非常快速且安全。

编辑:这是代码的改进版本。这会捕获错误,并在重新引发发出错误的异常之前清除临时文件。另外,正如J.F.Sebastian指出的那样,文件应该以二进制模式打开;这样做。

import fnmatch
import os
import shutil
import sys
import tempfile

file_patterns_to_match = ['*']

headertext = "# header text\n\n"
# make any newlines in headertext match the system line ending
headertext = headertext.replace('\n', os.linesep)

def want_this_file(fname):
    for pat in file_patterns_to_match:
        if fnmatch.fnmatch(fname, pat):
            return True
    return False

def prepend_file(fullname, path):
    # with statement means temp file is written and closed at end of with
    with tempfile.NamedTemporaryFile(dir=path, delete=False) as out_file:
        # get the name immediately
        temp_fname = out_file.name

        try:
            # use binary mode to avoid newline translations
            with open(fullname, "rb") as in_file:
                out_file.write(headertext)
                shutil.copyfileobj(in_file, out_file)
        except Exception:
            # on any error, clean up temp file and re-raise exception
            try:
                os.remove(temp_fname)
            except Exception:
                print("unable to clean up temp file: " + temp_fname)
                pass
            raise
    # rename temp file to fullname, clobbering original
    os.rename(temp_fname, fullname)


start_directory = sys.argv[1]

for dirpath, dirnames, filenames in os.walk(start_directory):
    for fname in filenames:
        if want_this_file(fname):
            fullname = os.path.join(dirpath, fname)
            prepend_file(fullname, dirpath)

答案 1 :(得分:0)

我知道你的问题是关于你的python脚本。但是你可以使用perl在bash中实现这一点。

sgeorge-mn:stack sgeorge$ cat file_0*
Hi - 1 
Hi - 2 
Hi - 3 
Hi - 4 
Hi - 5 

sgeorge-mn:stack sgeorge$ find . -type f
./file_01.txt
./file_02.txt
./file_03.txt
./file_04.txt
./file_05.txt

sgeorge-mn:stack sgeorge$ find . -type f -exec  perl -pi -e 'print "Please donot add any comments \nThis is a header file.\nJust a test.\n" if $. == 1' {} \;

sgeorge-mn:stack sgeorge$ cat file_0*
Please donot add any comments 
This is a header file.
Just a test.
Hi - 1 
Please donot add any comments 
This is a header file.
Just a test.
Hi - 2 
Please donot add any comments 
This is a header file.
Just a test.
Hi - 3 
Please donot add any comments 
This is a header file.
Just a test.
Hi - 4 
Please donot add any comments 
This is a header file.
Just a test.
Hi - 5