Как изменить текстовый файл? - PullRequest
155 голосов
/ 24 сентября 2008

Я использую Python и хотел бы вставить строку в текстовый файл без удаления или копирования файла. Как я могу это сделать?

Ответы [ 8 ]

127 голосов
/ 24 сентября 2008

К сожалению, нет способа вставить в середину файла, не переписав его. Как указывалось в предыдущих постерах, вы можете добавить файл или перезаписать его, используя поиск, но если вы хотите добавить материал в начале или в середине, вам придется переписать его.

Это вещь для операционной системы, а не для Python. Это одинаково на всех языках.

Обычно я читаю из файла, вносю изменения и записываю его в новый файл с именем myfile.txt.tmp или что-то в этом роде. Это лучше, чем чтение всего файла в память, потому что файл может быть слишком большим для этого. Как только временный файл будет завершен, я переименую его так же, как и исходный файл.

Это хороший, безопасный способ сделать это, потому что, если запись файла завершается сбоем или прерывается по какой-либо причине, у вас все еще остается ваш первозданный исходный файл.

94 голосов
/ 24 сентября 2008

Зависит от того, что вы хотите сделать. Чтобы добавить, вы можете открыть его с «а»:

 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
64 голосов
/ 28 ноября 2009

Модуль fileinput стандартной библиотеки Python перезапишет файл на месте, если вы используете параметр 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
31 голосов
/ 24 сентября 2008

Перезапись файла на месте часто выполняется путем сохранения старой копии с измененным именем. Люди 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+"~" )
14 голосов
/ 25 сентября 2008

Модуль Python mmap позволит вам вставить в файл. В следующем примере показано, как это можно сделать в Unix (в Windows mmap может отличаться). Обратите внимание, что это не обрабатывает все ошибки, и вы можете повредить или потерять исходный файл. Кроме того, это не будет обрабатывать строки 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 - что может быть огромным.

12 голосов
/ 20 ноября 2012

Как уже упоминал Адам, вы должны принять во внимание ограничения вашей системы, прежде чем вы сможете принять решение о подходе, достаточно ли у вас памяти, чтобы все это прочитать в память, заменить ее части и переписать.

Если вы работаете с небольшим файлом или у вас нет проблем с памятью, это может помочь:

Вариант 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()
1 голос
/ 02 ноября 2018

Если вы знаете какой-нибудь 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, проверьте это, это чрезвычайно полезно.

1 голос
/ 02 февраля 2016

Написал небольшой класс для этого чисто.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...