Я використовую Python і хотів би вставити рядок у текстовий файл, не видаляючи та не копіюючи файл. Як я можу це зробити?
Я використовую Python і хотів би вставити рядок у текстовий файл, не видаляючи та не копіюючи файл. Як я можу це зробити?
Відповіді:
На жаль, немає способу вставити в середину файлу, не перезаписавши його. Як було зазначено в попередніх плакатах, ви можете додати до файлу або перезаписати його частину за допомогою search, але якщо ви хочете додати матеріал на початку або в середині, вам доведеться переписати його.
Це річ операційної системи, а не річ Python. Це однаково у всіх мовах.
Що я зазвичай роблю, це читати з файлу, вносити зміни та записувати їх у новий файл під назвою myfile.txt.tmp або щось подібне. Це краще, ніж читати весь файл в пам'яті, тому що файл може бути занадто великим для цього. Після завершення тимчасового файлу я перейменую його так само, як і вихідний файл.
Це хороший, безпечний спосіб зробити це, тому що якщо файл з будь-якої причини виходить з ладу або перериває роботу, у вас все ще залишився недоторканий оригінальний файл.
Залежить від того, що ви хочете зробити. Щоб додати, ви можете відкрити його за допомогою "a":
with open("foo.txt", "a") as f:
f.write("new line\n")
Якщо ви хочете попередньо підготувати щось, що вам потрібно спочатку прочитати з файлу:
with open("foo.txt", "r+") as f:
old = f.read() # read everything in the file
f.seek(0) # rewind
f.write("new line\n" + old) # write the new line before
with
оператор у Python 2.5, вам потрібно додати "з майбутнього імпорту з_держанням". Крім цього, відкриття файлів із with
заявою, безумовно, є більш читабельним та менш схильним до помилок, ніж закриття вручну.
fileinput
вкладка-помічник із ручками брудно відкривається / читає / модифікує / записує / замінює рутину при використанні inline=True
аргументу. Приклад тут: stackoverflow.com/a/2363893/47390
f.Close()
fileinput
Модуль стандартної бібліотеки Python перепише файл InPlace , якщо ви використовуєте INPLACE параметр = 1:
import sys
import fileinput
# replace all occurrences of 'sit' with 'SIT' and insert a line after the 5th
for i, line in enumerate(fileinput.input('lorem_ipsum.txt', inplace=1)):
sys.stdout.write(line.replace('sit', 'SIT')) # replace 'sit' and write
if i == 4: sys.stdout.write('\n') # write a blank line after the 5th line
Переписування файлу на місці часто виконується шляхом збереження старої копії із зміненим іменем. Unix люди додають, ~
щоб позначити старий. Люди з Windows роблять всілякі речі - додають .bak або .old - або перейменують файл цілком або ставлять ~ на передній частині імені.
import shutil
shutil.move( afile, afile+"~" )
destination= open( aFile, "w" )
source= open( aFile+"~", "r" )
for line in source:
destination.write( line )
if <some condition>:
destination.write( >some additional line> + "\n" )
source.close()
destination.close()
Замість цього shutil
можна використовувати наступне.
import os
os.rename( aFile, aFile+"~" )
os.rename(aFile, aFile + "~")
змінить ім'я вихідного файлу, не створивши копію.
Mmap-модуль Python дозволить вам вставити у файл. Наступний зразок показує, як це можна зробити в Unix (mmap Windows може бути різним). Зауважте, що це не обробляє всі умови помилки, і ви можете пошкодити або втратити оригінальний файл. Крім того, це не буде обробляти рядки Unicode.
import os
from mmap import mmap
def insert(filename, str, pos):
if len(str) < 1:
# nothing to insert
return
f = open(filename, 'r+')
m = mmap(f.fileno(), os.path.getsize(filename))
origSize = m.size()
# or this could be an error
if pos > origSize:
pos = origSize
elif pos < 0:
pos = 0
m.resize(origSize + len(str))
m[pos+len(str):] = m[pos:origSize]
m[pos:pos+len(str)] = str
m.close()
f.close()
Це також можна зробити без mmap з файлами, відкритими в режимі 'r +', але це менш зручно і менш ефективно, оскільки вам доведеться читати і тимчасово зберігати вміст файлу з позиції вставки до EOF - що може бути величезним.
Як згадував Адам, ви повинні врахувати свої системні обмеження, перш ніж ви зможете визначитися з підходом, чи вистачить вам пам'яті, щоб прочитати все це в пам'яті, замінити її частини та переписати.
Якщо ви маєте справу з невеликим файлом або не маєте проблем із пам'яттю, це може допомогти:
Варіант 1) Прочитайте весь файл в пам'яті, зробіть підстановку з регулярними виразами на всій або частині рядка та замініть його на цей рядок плюс додатковий рядок. Вам потрібно буде переконатися, що "середня лінія" є унікальною у файлі, або якщо у вас є часові позначки на кожному рядку, це повинно бути досить надійним.
# open file with r+b (allow write and binary mode)
f = open("file.log", 'r+b')
# read entire content of file into memory
f_content = f.read()
# basically match middle line and replace it with itself and the extra line
f_content = re.sub(r'(middle line)', r'\1\nnew line', f_content)
# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)
# clear file content
f.truncate()
# re-write the content with the updated content
f.write(f_content)
# close file
f.close()
Варіант 2) Визначте середню лінію та замініть її на цю лінію плюс додаткову.
# open file with r+b (allow write and binary mode)
f = open("file.log" , 'r+b')
# get array of lines
f_content = f.readlines()
# get middle line
middle_line = len(f_content)/2
# overwrite middle line
f_content[middle_line] += "\nnew line"
# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)
# clear file content
f.truncate()
# re-write the content with the updated content
f.write(''.join(f_content))
# close file
f.close()
Написав невеликий клас для того, щоб це робити чисто.
import tempfile
class FileModifierError(Exception):
pass
class FileModifier(object):
def __init__(self, fname):
self.__write_dict = {}
self.__filename = fname
self.__tempfile = tempfile.TemporaryFile()
with open(fname, 'rb') as fp:
for line in fp:
self.__tempfile.write(line)
self.__tempfile.seek(0)
def write(self, s, line_number = 'END'):
if line_number != 'END' and not isinstance(line_number, (int, float)):
raise FileModifierError("Line number %s is not a valid number" % line_number)
try:
self.__write_dict[line_number].append(s)
except KeyError:
self.__write_dict[line_number] = [s]
def writeline(self, s, line_number = 'END'):
self.write('%s\n' % s, line_number)
def writelines(self, s, line_number = 'END'):
for ln in s:
self.writeline(s, line_number)
def __popline(self, index, fp):
try:
ilines = self.__write_dict.pop(index)
for line in ilines:
fp.write(line)
except KeyError:
pass
def close(self):
self.__exit__(None, None, None)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
with open(self.__filename,'w') as fp:
for index, line in enumerate(self.__tempfile.readlines()):
self.__popline(index, fp)
fp.write(line)
for index in sorted(self.__write_dict):
for line in self.__write_dict[index]:
fp.write(line)
self.__tempfile.close()
Тоді ви можете використовувати це таким чином:
with FileModifier(filename) as fp:
fp.writeline("String 1", 0)
fp.writeline("String 2", 20)
fp.writeline("String 3") # To write at the end of the file
Якщо ви знаєте деякі Unix, ви можете спробувати наступне:
Примітки: $ означає командний рядок
Скажімо, у вас є файл my_data.txt із таким вмістом:
$ cat my_data.txt
This is a data file
with all of my data in it.
Потім за допомогою os
модуля можна використовувати звичайні sed
команди
import os
# Identifiers used are:
my_data_file = "my_data.txt"
command = "sed -i 's/all/none/' my_data.txt"
# Execute the command
os.system(command)
Якщо ви не знаєте sed, перевірте це, це надзвичайно корисно.