ファイルの先頭にテキストが必要な場合は、次のようにする必要があります。
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)
上記をPython2.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"
)を使用し、そのファイルは常に単一のディレクトリ(これを実行するときのデフォルトディレクトリ)に作成されます。本当に必要なのは、編集するファイルとまったく同じディレクトリに作成された、一意の名前の一時ファイルです。tempfile
Pythonには、一時ファイルを作成するという便利なモジュールが用意されています。
デフォルトでは、開いているファイルハンドルを取得するだけで、ファイル名はわかりません。ただし、一時コピーが完全に完了した後、元のファイル名に名前を変更できるように、ファイル名を知る必要があります。 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
あり、そこに一時ファイルを作成するだけの場合、名前変更操作にはデータの再コピーが含まれる可能性があります。一時ファイルが同じディレクトリにある場合、名前変更操作は常に非常に高速で安全です。
編集:これはコードの改良版です。これによりエラーがキャッチされ、エラーを通知する例外を再発生させる前に一時ファイルがクリーンアップされます。また、JFセバスティアンが指摘したように、ファイルはバイナリモードで開く必要があります。これはそれを行います。
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)