Как вставить текст в строку и позицию столбца в файле?

Я хотел бы вставить строку в определенный столбец определенной строки в файле.

Предположим, у меня есть файл file.txt

How was the English test?
How was the Math test?
How was the Chemistry test?
How was the test?

Я хотел бы изменить последнюю строку, чтобы сказать, How was the History test? добавив строку History в строке 4 столбца 13.

В настоящее время я читаю в каждой строке файла и добавляю строку в указанную позицию.

with open("file.txt", "r+") as f:
    # Read entire file
    lines = f.readlines()

    # Update line
    lino = 4 - 1
    colno = 13 -1
    lines[lino] = lines[lino][:colno] + "History " + lines[lino][colno:]

    # Rewrite file
    f.seek(0)
    for line in lines:
        f.write(line)
    f.truncate()
    f.close()

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

Ответ 1

Возможно, это дубликат ниже SO-потока

Самый быстрый способ удалить строку из большого файла в Python

В приведенном выше разговоре об удалении, который является всего лишь манипуляцией, и ваш, скорее, является модификацией. Таким образом, код будет обновляться, как показано ниже.

def update(filename, lineno, column, text):
    fro = open(filename, "rb")

    current_line = 0
    while current_line < lineno - 1:
        fro.readline()
        current_line += 1

    seekpoint = fro.tell()
    frw = open(filename, "r+b")
    frw.seek(seekpoint, 0)

    # read the line we want to update
    line = fro.readline()
    chars = line[0: column-1] + text + line[column-1:]

    while chars:
        frw.writelines(chars)
        chars = fro.readline()

    fro.close()
    frw.truncate()
    frw.close()


if __name__ == "__main__":
    update("file.txt", 4, 13, "History ")

В большом файле имеет смысл не модифицировать до lineno, где должно произойти обновление, представьте, что у вас есть файл с линиями 10K, и обновление должно произойти в 9K, ваш код будет излишне загружать все 9K строк данных в памяти. Код, который у вас есть, будет работать, но это не оптимальный способ сделать это

Ответ 2

Вы можете использовать этот фрагмент кода:

with open("test.txt",'r+') as f:
    # Read the file 
    lines=f.readlines()

    # Gets the column
    column=int(input("Column:"))-1

    # Gets the line
    line=int(input("Line:"))-1

    # Gets the word
    word=input("Word:")

    lines[line]=lines[line][0:column]+word+lines[line][column:]

    # Delete the file
    f.seek(0)

    for i in lines:
        # Append the lines
        f.write(i)

Ответ 3

Функция readlines() считывает весь файл. Но это не обязательно. Фактически он считывает из текущей позиции курсора в файл до конца, что бывает 0 сразу после открытия. (Чтобы убедиться в этом, попробуйте f.tell() сразу же после того, как with утверждением.) Что делать, если мы начали ближе к концу файла?

Способ написания вашего кода подразумевает некоторые предварительные знания о ваших файлах и макетах. Можете ли вы установить ограничения на каждую строку? Например, учитывая ваши данные примера, мы можем сказать, что строки гарантированно составляют 27 байтов или меньше. Позвольте обвести это до 32 для "силы 2-ness" и попытайтесь найти назад от конца файла.

# note the "rb+"; need to open in binary mode, else seeking is strictly
# a "forward from 0" operation.  We need to be able to seek backwards
with open("file.txt", "rb+") as f:
    # caveat: if file is less than 32 bytes, this will throw
    # an exception.  The second parameter, 2, says "from end of file"
    f.seek(-32, 2)

    last = f.readlines()[-1].decode()

В этот момент код только считывает последние 32 байта файла. 1readlines() (на уровне байта) будет искать байт конца строки (в Unix, \n или 0x0a или значение байта 10) и вернуть до и после. Изложены:

>>> last = f.readlines()
>>> print( last )
[b'hemistry test?\n', b'How was the test?']

>>> last = last[-1]
>>> print( last )
b'How was the test?'

Реально, это работает в соответствии с кодировкой UTF-8, используя свойство UTF-8, что значения байтов ASCII ниже 128 не возникают при кодировании байтов без ASCII. Другими словами, точный байт \n (или 0x0a) только когда-либо встречается как символ новой строки и никогда не является частью символа. Если вы используете кодировку, отличную от UTF-8, вам нужно будет проверить, сохраняются ли предположения кода.

Другое примечание: 32 байта произвольны с учетом данных примера. Более реалистичным и типичным значением может быть 512, 1024 или 4096. Наконец, вернемся к рабочему примеру для вас:

with open("file.txt", "rb+") as f:
    # caveat: if file is less than 32 bytes, this will throw
    # an exception.  The second parameter, 2, says "from end of file"
    f.seek(-32, 2)

    # does *not* read while file, unless file is exactly 32 bytes.
    last = f.readlines()[-1]
    last_decoded = last.decode()

    # Update line
    colno = 13 -1
    last_decoded = last_decoded[:colno] + "History " + last_decoded[colno:]

    last_line_bytes = len( last )
    f.seek(-last_line_bytes, 2)
    f.write( last_decoded.encode() )
    f.truncate()

Обратите внимание, что нет необходимости в f.close(). Оператор with обрабатывает это автоматически.

1 Педантик правильно отметит, что компьютер и ОС, скорее всего, прочитали не менее 512 байт, если не 4096 байт, относящихся к размеру страницы на диске или в памяти.

Ответ 4

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

def insert(file, line, column, text):
    ln, cn = line - 1, column - 1         # offset from human index to Python index
    count = 0                             # initial count of characters
    with open(file, 'r+') as f:           # open file for reading an writing
        for idx, line in enumerate(f):    # for all line in the file
            if idx < ln:                  # before the given line
                count += len(line)        # read and count characters 
            elif idx == ln:               # once at the line                                 
                f.seek(count + cn)        # place cursor at the correct character location
                remainder = f.read()      # store all character afterwards                       
                f.seek(count + cn)        # move cursor back to the correct character location
                f.write(text + remainder) # insert text and rewrite the remainder
                return                    # You're finished!

Ответ 5

Я не уверен, были ли у вас проблемы с изменением файла, чтобы он содержал слово "История", или вы хотели знать, как переписывать определенные части файла, не переписывая все это.

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

fileData="""How was the English test?
How was the Math test?
How was the Chemistry test?
How was the test?""" # So that I don't have to create the file, I'm writing the text directly into a variable.
fileData=fileData.split("\n")
fileData[3]=fileData[3][:11]+" History"+fileData[3][11:] # The 3 referes to the line to add "History" to. (The first line is line 0)
storeData=""
for i in fileData:storeData+=i+"\n"
storeData=storeData[:-1]
print(storeData) # You can change this to a write command.

Если вы хотите знать, как изменить определенные "части" в файле, не переписывая все это, то, насколько мне известно, это невозможно.

Скажем, у вас есть файл, в котором говорится, что Ths is a TEST file. , и вы хотели исправить это, чтобы сказать, This is a TEST file. ; вы бы технически меняли 17 символов и добавляли один на конец. Вы меняете "s" на "i", первое место на "s", "i" (от "is") до пробела и т.д., Когда вы перемещаете текст вперед.

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

Ответ 6

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

Корень этой кажущейся простой, вероятно, является вашей ментальной моделью файла. скорее всего, метафора, используемая вами, является листом бумаги. (поощряется визуализация файлов как кусков бумаги в графических интерфейсах) на листе бумаги есть много свободного места для вставки вещей, и изменение только одной строки кажется простым, вы просто стираете "тест"? а затем написать "Тест истории?" а дополнительные символы просто означают, что линия немного длиннее, и на этой линии меньше пробела. никакие другие линии не нужно трогать, просто.....

К сожалению, лист бумаги не похож на реальность текстового файла. Текстовый файл по существу представляет собой длинный список символов (группы бит), причем символы новой строки являются всего лишь другим символом (обычно представленным /n так что это действительно похоже на:

"Как прошел тест на английском языке?\NКак был тест на математику?\NКак был тест на химию?\NКак был тест? \Nhow был тест программирования?"

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

Это сводится к тому, что, поскольку вам нужно будет продлить файл и переписать все после редактирования, это не стоит делать. Если вы не имеете дело с массивными текстовыми файлами, которые могут не вписываться в ram. Его путь проще и не менее эффективен для

  1. Прочитайте весь файл в ОЗУ
  2. Изменить его
  3. Напишите весь файл на диск.

Это может показаться неэффективным, но это то, что компьютеры делают хорошо. Если вы хотите повысить эффективность работы ОЗУ, вы можете превратить объемную операцию в поток, пронумеровав строку за строкой.

  1. Прочитайте строку из файла в память,
  2. Измените строку (или нет)
  3. Запись строки в новый файл

См. Несколько других примеров для фактического кода, чтобы сделать это, цель моих ответов - решить, почему вставка текста в файл кажется небольшой простой операцией для файла, но на самом деле это не так.