Python - удалить самый последний символ в файле

Посмотрев весь интернет, я пришел к этому.

Допустим, я уже сделал текстовый файл, который гласит:Hello World

Ну, я хочу удалить самый последний символ (в этом случае d) из этого текстового файла.

Теперь текстовый файл должен выглядеть так: Hello Worl

Но я понятия не имею, как это сделать.

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

Это должно работать на Linux, поскольку это то, что я использую.

8 ответов

Решение

Использование file.seek() искать 1 позицию с конца, затем использовать file.truncate() чтобы удалить оставшуюся часть файла:

with open(filename, 'rb+') as filehandle:
    filehandle.seek(-1, os.SEEK_END)
    filehandle.truncate()

Принятый ответ Martijn прост и отчасти работает, но не учитывает текстовые файлы с:

  • Кодировка UTF-8, содержащая неанглийские символы (которая является кодировкой по умолчанию для текстовых файлов в Python 3)
  • один символ новой строки в конце файла (по умолчанию в редакторах Linux, таких как vim или же gedit)

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

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

import os


def truncate_utf8_chars(filename, count, ignore_newlines=True):
    """
    Truncates last `count` characters of a text file encoded in UTF-8.
    :param filename: The path to the text file to read
    :param count: Number of UTF-8 characters to remove from the end of the file
    :param ignore_newlines: Set to true, if the newline character at the end of the file should be ignored
    """
    with open(filename, 'rb+') as f:
        last_char = None

        size = os.fstat(f.fileno()).st_size

        offset = 1
        chars = 0
        while offset <= size:
            f.seek(-offset, os.SEEK_END)
            b = ord(f.read(1))

            if ignore_newlines:
                if b == 0x0D or b == 0x0A:
                    offset += 1
                    continue

            if b & 0b10000000 == 0 or b & 0b11000000 == 0b11000000:
                # This is the first byte of a UTF8 character
                chars += 1
                if chars == count:
                    # When `count` number of characters have been found, move current position back
                    # with one byte (to include the byte just checked) and truncate the file
                    f.seek(-1, os.SEEK_CUR)
                    f.truncate()
                    return
            offset += 1

Как это устроено:

  • Читает только последние несколько байтов текстового файла в кодировке UTF-8 в двоичном режиме
  • Итерирует байты в обратном направлении, ища начало символа UTF-8
  • Как только будет найден символ (отличный от новой строки), верните его как последний символ в текстовом файле.

Образец текстового файла - bg.txt:

Здравей свят

Как пользоваться:

filename = 'bg.txt'
print('Before truncate:', open(filename).read())
truncate_utf8_chars(filename, 1)
print('After truncate:', open(filename).read())

Выходы:

Before truncate: Здравей свят
After truncate: Здравей свя

Это работает с файлами в кодировке UTF-8 и ASCII.

Если вы не читаете файл в двоичном режиме, где у вас есть только права доступа "w", я могу предложить следующее.

f.seek(f.tell() - 1, os.SEEK_SET)
f.write('')

В этом коде выше, f.seek() будет принимать только f.tell() б / у у вас нет доступа 'б'. тогда вы можете установить курсор на начало последнего элемента. Затем вы можете удалить последний элемент пустой строкой.

with open(urfile, 'rb+') as f:
    f.seek(0,2)                 # end of file
    size=f.tell()               # the size...
    f.truncate(size-1)          # truncate at that size - how ever many characters

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

with open('file.txt', 'w') as f:
    f.seek(0, 2)              # seek to end of file; f.seek(0, os.SEEK_END) is legal
    f.seek(f.tell() - 2, 0)  # seek to the second last char of file; f.seek(f.tell()-2, os.SEEK_SET) is legal
    f.truncate()

в зависимости от того, какой последний символ в файле, может быть новая строка (\n) или что-то еще.

Это может быть неоптимально, но если вышеперечисленные подходы не сработают, вы можете сделать:

      with open('myfile.txt', 'r') as file:
    data = file.read()[:-1]
with open('myfile.txt', 'w') as file:
    file.write(data)

Код сначала открывает файл, а затем копирует его содержимое (за исключением последнего символа) в строку. После этого файл обрезается до нулевой длины (т.е. очищается), а содержимое сохраняется в файл с тем же именем. Это в основном то же самое, что и ответ vins ms, за исключением того, что он не использует пакет os и используется более безопасный синтаксис «с открытым». Это не рекомендуется, если текстовый файл большой. (Я написал это, поскольку ни один из вышеперечисленных подходов не сработал для меня в python 3.8).

В системе Linux или (Cygwin в Windows). Вы можете использовать стандартную команду усечения. Вы можете уменьшить или увеличить размер вашего файла с помощью этой команды.

Чтобы уменьшить файл на 1 ГБ, команда будет truncate -s 1G filename. В следующем примере я уменьшаю файл с именемupdate.iso пользователя 1G.

Обратите внимание, что эта операция заняла менее пяти секунд.

chris@SR-ENG-P18 /cygdrive/c/Projects
$ stat update.iso
  File: update.iso
  Size: 30802968576     Blocks: 30081024   IO Block: 65536  regular file
Device: ee6ddbceh/4000177102d   Inode: 19421773395035112  Links: 1
Access: (0664/-rw-rw-r--)  Uid: (1052727/   chris)   Gid: (1049089/Domain Users)
Access: 2020-06-12 07:39:00.572940600 -0400
Modify: 2020-06-12 07:39:00.572940600 -0400
Change: 2020-06-12 07:39:00.572940600 -0400
 Birth: 2020-06-11 13:31:21.170568000 -0400

chris@SR-ENG-P18 /cygdrive/c/Projects
$ truncate -s -1G update.iso

chris@SR-ENG-P18 /cygdrive/c/Projects
$ stat update.iso
  File: update.iso
  Size: 29729226752     Blocks: 29032448   IO Block: 65536  regular file
Device: ee6ddbceh/4000177102d   Inode: 19421773395035112  Links: 1
Access: (0664/-rw-rw-r--)  Uid: (1052727/   chris)   Gid: (1049089/Domain Users)
Access: 2020-06-12 07:42:38.335782800 -0400
Modify: 2020-06-12 07:42:38.335782800 -0400
Change: 2020-06-12 07:42:38.335782800 -0400
 Birth: 2020-06-11 13:31:21.170568000 -0400

В stat Команда сообщает вам много информации о файле, включая его размер.

Вот грязный способ (стереть и воссоздать)... я не советую использовать это, но, возможно, сделать так...

x = open("file").read()
os.remove("file")
open("file").write(x[:-1])
Другие вопросы по тегам