2013-01-09 141 views
2

我有下面的代码,除了我想要的:-)。目标很简单,我试图将文本添加到目录中每个文件顶部的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) 
+1

“附加”表示“添加到结尾”。你想要的是“预先安排”。 –

+0

@FrancisAvila - 问题是它甚至没有附加文本结束..如果它的工作,我可以尝试chagne预先 – user1934146

+0

是否打印fnmatch.filter(文件,拍)产生任何东西? – jfs

回答

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.塞巴斯蒂安指出的,文件应该以二进制模式打开;这是做的。

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) 
+0

steveha - 我正在使用pythong 2.6.5,在打开(fullname,“r”)时将in_file,open(temp_fname,“w”)编译为out_file: ^ SyntaxError:无效的语法,有没有办法我们可以在不创建临时文件的情况下在python 2.6.5中执行此操作 – user1934146

+0

您可以通过将整个文件读入内存然后覆盖该文件来执行此操作,而无需临时文件。 *但是*,临时文件更安全并使用更少的内存。无法再将整个文件写出来,这是不可能的。 –

+0

@ user1934146:手动嵌套with语句。 – jfs

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 
+1

'find/start/dir -type f -exec sed -i'1i line prepend'{} +' – jfs