Как использовать бинарные файлы. Перезапись определенных байтов - PullRequest
0 голосов
/ 30 октября 2018

Я пишу программу на python и хотел бы иметь возможность записывать определенные байты в двоичном файле. Я попытался сделать это в оболочке с небольшим двоичным файлом, содержащим цифры от 0 до 15, но я не могу понять, как это сделать. Ниже приведен код, который я только что ввел в оболочку с комментариями, чтобы продемонстрировать, что я пытаюсь сделать:

>>> File=open("TEST","wb") # Opens the file for writing.
>>> File.write(bytes(range(16))) # Writes the numbers 0 through 15 to the file.
16
>>> File.close() # Closes the file.
>>> File=open("TEST","rb") # Opens the file for reading, so that we can test that its contents are correct.
>>> tuple(File.read()) # Expected output: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
>>> File.close() # Closes the file.
>>> File=open("TEST","wb") # Opens the file for writing.
>>> File.seek(3) # Moves the pointer to position 3. (Fourth byte.)
3
>>> File.write(b"\x01") # Writes 1 to the file in its current position.
1
>>> File.close() # Closes the file.
>>> File=open("TEST","rb") # Opens the file for reading, so that we can test that its contents are correct.
>>> tuple(File.read()) # Expected output: (0, 1, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
(0, 0, 0, 1)
>>> File.close()
>>> File=open("TEST","wb") # I will try again using apend mode to overwrite.
>>> File.write(bytes(range(16)))
16
>>> File.close()
>>> File=open("TEST","ab") # Append mode.
>>> File.seek(3)
3
>>> File.write(b"\x01")
1
>>> File.close()
>>> File=open("TEST","rb")
>>> tuple(File.read()) # Expected output: (0, 1, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1)
>>> File.close()

Мой желаемый вывод такой, как показано, но "wb", кажется, удаляет все данные в файле, в то время как "ab" не может искать в обратном направлении.

Как бы я достиг желаемого результата без перезаписи всего файла?

Ответы [ 3 ]

0 голосов
/ 30 октября 2018

Если я правильно помню, вы должны открыть файл в «режиме добавления», или он просто сотрет все и начнет с нуля, а затем, когда вы используете seek(3), вы просто создаете эти 3 0 и затем пишете 1 Далее я расскажу о том, как писать напрямую в позицию, но вам, возможно, придется прочитать весь файл, изменить, снова записать весь файл.

Вы можете прочитать об этом поведении в документации :

'w' только для записи (существующий файл с тем же именем будет удален)

0 голосов
/ 30 октября 2018

Решение в другом режиме: "r+b". (как показывают другие ответы.)

Вот решение в оболочке, откуда файл остановился:

>>> File=open("TEST","r+b") # Opens file for reading and writing.
>>> File.seek(3)
3
>>> File.write(b"\x01")
1
>>> File.close()
>>> File=open("TEST","rb")
>>> tuple(File.read()) # Expected output: (0, 1, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1)
(0, 1, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1)
>>> File.close()
0 голосов
/ 30 октября 2018

Когда вы открываете файл для записи с помощью w, файл усекается , все содержимое удаляется. Вам нужно открыть файл для чтения и записи с помощью r+. Из документации по open():

'w' открыть для записи, сначала обрезать файл

и

Для двоичного доступа на чтение и запись, режим 'w + b' открывает и усекает файл до 0 байт. 'r + b' открывает файл без усечения.

Поскольку файл был сначала обрезан, при поиске позиции 3 и записи \x01 первые несколько байтов заполнены \x00 для вас.

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

Другими общими значениями являются [...] и 'a' для добавления (, что в некоторых системах Unix означает, что все записи добавляются в конец файла независимо от текущей позиции поиска ).

( выделение жирным шрифтом в цитируемых разделах шахты ). Вот почему ваш \x01 байт заканчивается в самом конце, несмотря на вызов File.seek(3).

r не усекает файл и предоставляет полный диапазон содержимого с помощью seek(); r+ добавляет доступ для записи в этот режим. Демо с 'r+b':

>>> with open('demo.bin', 'wb') as f:
...     f.write(bytes(range(16)))
...
16
>>> with open('demo.bin', 'rb') as f:
...     print(*f.read())
...
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
>>> with open('demo.bin', 'r+b') as f:  # read and write mode
...     f.seek(3)
...     f.write(b'\x01')
...
3
1
>>> with open('demo.bin', 'rb') as f:
...     print(*f.read())
...
0 1 2 1 4 5 6 7 8 9 10 11 12 13 14 15
...