Python3 (v3.2.2) дополнительные биты при записи двоичных файлов - PullRequest
2 голосов
/ 26 октября 2011

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

with open(self._path,'r+b') as source:
    for lookAt in range(0,self._size[1]*self._size[2],1):
        source.seek(lookAt*self._size[0],0)
        readBuffer = array.array('B')
        readBuffer.fromfile(source, self._size[0])
        newLine = array.array('B',[mappingDict[mat] for mat in readBuffer])
        source.seek(lookAt*self._size[0],0)
        newLine.tofile(source)
        source.seek(0,2) # Magic line that solves stupid bug
source.close()

Я использую модуль массива для чтения и записи данных, поскольку у меня возникла та же проблема, когда я использовал read () и write (). Я не понимаю, почему «Волшебная линия» решает проблему, поскольку она никогда не использовалась. Я буду признателен за любую информацию, которую я могу получить по этому поводу.

Ответы [ 2 ]

3 голосов
/ 26 октября 2011

Комментарий (ответ следует):

Я вижу то же поведение, что и вы:

#!/usr/bin/env python3
import os
import sys

filename = '/tmp/a'
with open(filename, 'wb') as f:
    f.write(b'1234a67b8ca')
print(open(filename, 'rb').read())

bufsize = 3

table = bytes.maketrans(b'abcde', b'xyzzz') # mapping
with open(filename, 'r+b') as f:
    for i in range(0, os.path.getsize(filename), bufsize):
        f.seek(i, os.SEEK_SET)
        b = f.read(bufsize) # result shouldn't depend on it due to 1 -> 1
        if not b: 
            break
        f.seek(i, os.SEEK_SET)
        f.write(b.translate(table))
        f.seek(0, os.SEEK_END) # magic
print(open(filename, 'rb').read())

Вывод (с магической линией или буферизацией = 0 или f.flush () после f.запись)

b'1234a67b8ca'
b'1234x67y8zx'

Вывод (без магической линии)

b'1234a67b8ca'
b'1234a67b8zx1234x67y8'

Ответ:

Если ваше отображение равно 1 -> 1, вы можете использовать bytes.translate():

#!/usr/bin/env python3
import io
import os
import sys

filename = '/tmp/a'
data = b'1234a67b8ca'*10000
with open(filename, 'wb') as f:
    f.write(data)
assert data == open(filename, 'rb').read()
print(data[:10]+data[-10:])

bufsize = io.DEFAULT_BUFFER_SIZE

table = bytes.maketrans(b'abcde', b'xyzzz') # mapping
with open(filename, 'r+b') as f:
    while True:
        b = f.read(bufsize) # result shouldn't depend on bufsize due to 1 -> 1
        if not b: 
            break
        f.seek(-len(b), os.SEEK_CUR)
        f.write(b.translate(table))
        f.flush()

tr_data = data.translate(table)
assert tr_data  == open(filename, 'rb').read()
print(tr_data[:10]+tr_data[-10:])

Кажется, что io.BufferedRandom не может сделать чересстрочное чтение / поиск / запись (ошибка в Python3) без flush().

1 голос
/ 26 октября 2011

Немного поэкспериментировав, я предполагаю, что это ошибка в Python 3.

В поддержку моей гипотезы я предлагаю следующий код (на основе @JF Себастьяна):

import os
import sys

filename = '/tmp/a'
with open(filename, 'wb') as f:
    f.write(b'1234a67b8ca')
print(open(filename, 'rb').read())

bufsize = 3

with open(filename, 'r+b') as f:
    for i in range(0, os.path.getsize(filename), bufsize):
        f.seek(i, os.SEEK_SET)
        b = f.read(bufsize)
        f.seek(i, os.SEEK_SET)
        f.write(b)
#        f.seek(0, os.SEEK_END) # magic
print(open(filename, 'rb').read())

При запуске с использованием Python 2.7.1 он работает так, как вы ожидаете, и магическая линия не имеет значения.

При запуске с использованием Python 3.1.2 , это необъяснимо требует волшебной неактивности seek(), чтобы заставить ее работать как положено.

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

...