Запись двоичного буфера в файл в Python - PullRequest
6 голосов
/ 17 марта 2009

У меня есть код Python, который:

  1. Извлекает BLOB из сжатой базы данных.
  2. Вызывает процедуру распаковки в C, которая распаковывает данные.
  3. Записывает несжатые данные в файл.

Он использует ctypes для вызова подпрограммы C, которая находится в общей библиотеке.

Это в основном работает, за исключением фактической записи в файл. Чтобы распаковать данные, я распаковываю данные в буфер python, созданный с помощью метода ctypes create_string_buffer:

c_uncompData_p = create_string_buffer(64000)

так что несжатый вызов такой:

c_uncompSize = mylib.explodeCharBuffer (c_data_p, c_data_len, c_uncompData_p)

Размер полученных несжатых данных возвращается в качестве возвращаемого значения.

Но ... я понятия не имею, как заставить Python только писать c_uncompSize байтов - если я делаю:

myfile.write (c_uncompData_p.raw)

он записывает весь буфер 64 КБ (данные являются двоичными - так что они не заканчиваются нулем).

Итак, мой вопрос - используя Python 2.5, как получить распечатанные байты c_uncompSize вместо целых 64 КБ?

Спасибо Джейми

Ответы [ 2 ]

6 голосов
/ 17 марта 2009

buffer() может помочь избежать ненужного копирования (вызвано нарезкой, как в @ elo80ka's answer ):

myfile.write(buffer(c_uncompData_p.raw, 0, c_uncompSize))

В вашем примере это не имеет значения (поскольку c_uncompData_p записывается только один раз и оно маленькое), но в целом это может быть полезно.


Только ради упражнений вот ответ, который использует C stdio s fwrite():

from ctypes import *

# load C library
try: libc = cdll.msvcrt # Windows
except AttributeError:
     libc = CDLL("libc.so.6") # Linux

# fopen()
libc.fopen.restype = c_void_p
def errcheck(res, func, args):
    if not res: raise IOError
    return res
libc.fopen.errcheck = errcheck
# errcheck() could be similarly defined for `fwrite`, `fclose` 

# write data
file_p  = libc.fopen("output.bin", "wb")
sizeof_item = 1 # bytes
nitems  = libc.fwrite(c_uncompData_p, sizeof_item, c_uncompSize, file_p)
retcode = libc.fclose(file_p)
if nitems != c_uncompSize: # not all data were written
   pass
if retcode != 0: # the file was NOT successfully closed
   pass
6 голосов
/ 17 марта 2009

Нарезка работает и для c_char_Arrays:

myfile.write(c_uncompData_p[:c_uncompSize])
...