Как я могу запустить программу из python в файле, который находится в памяти?

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

Есть ли способ вызвать subprocess.Popen, чтобы я мог передать файл в памяти утилите командной строки, которую команда будет понимать как файл? Я попытался присвоить дескриптор файла стандартному вводу, но утилиты не читают содержимое файла из стандартного ввода, как ожидалось.

with zipfile.ZipFile(file,'r') as z:
  with z.open(binary_path) as bin:
    subprocess.Popen(['readelf','-d'],stdin=bin)

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

with zipfile.ZipFile(file,'r') as z:
  with z.open(binary_path) as bin:
    subprocess.Popen(['readelf','-d',bin])

Возможно ли то, что я пытаюсь сделать, или я должен просто прибегнуть к записи на диск и анализу оттуда?

Большое спасибо!


person JymmyZ    schedule 12.12.2012    source источник
comment
Вы не можете записать содержимое bin во временный файл на диске? В качестве альтернативы, можете ли вы использовать RAM-диск (если производительность является проблемой)?   -  person Andre Holzner    schedule 12.12.2012
comment
@AndreHolzner: Он прямо в первом абзаце говорит, что не хочет записывать двоичные файлы на диск. Он может ошибаться в том, что это реальная стоимость (или ему просто нужно найти лучший способ сделать это), но он явно обдумал основную идею.   -  person abarnert    schedule 13.12.2012


Ответы (1)


Zeroth, зачем тебе popen readelf вместо использования libelf или чего-то подобного? Быстрый поиск "elf" в PyPI показывает множество возможностей. Вы их просмотрели?

Во-первых, на многих платформах все операции ввода-вывода в конечном итоге будут проходить через кеш, так что это не сильно замедлит работу, даже если в конечном итоге все будет сброшено на диск только для того, чтобы удалить его (что может никогда не произойти). делать). Осторожное использование mmap часто может помочь избежать сброса на диск, но вам это может даже не понадобиться.

Так что на самом деле я бы сначала протестировал его и посмотрел, действительно ли чрезмерный ввод-вывод замедляет вас. Если нет, перестаньте об этом беспокоиться.

Если вы хотите быть уверены, что дисковый ввод-вывод отсутствует (я предполагаю, что вы отключили все подкачки, потому что в противном случае эта идея изначально бессмысленна), самое простое решение — создать временный файл, который на самом деле не скопировано на диск.

Самый простой способ сделать это — создать виртуальный диск и просто поместить туда временные файлы.

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

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

with zipfile.ZipFile(file,'r') as z:
    with z.open(binary_path) as bin:
        subprocess.Popen(['gzip','-dc'], stdin=bin)

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

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

person abarnert    schedule 12.12.2012
comment
Спасибо за множество полезных комментариев! Я пытался использовать pyelftools, но я работаю с двоичными файлами ARM, и мне нужно определить, от каких библиотек зависит файл, обе из которых, похоже, не поддерживаются модулем. Я пытался взломать поддержку, но я не очень хорошо разбираюсь в низкоуровневом кодировании, необходимом для правильной работы. Я проверю любые другие модули, которые я мог пропустить, чтобы увидеть, способны ли они обеспечить необходимую мне функциональность, но я довольно хорошо изучил Интернет, чтобы понять это. ТАК мое последнее средство. - person JymmyZ; 13.12.2012
comment
@JymmyZ: Большинство библиотек кажутся парсерами ELF на чистом Python; может быть, тот, который обертывает libelf, будет иметь больше функциональности — или, если такой библиотеки нет, может быть, использовать Cython или ctypes для прямого общения с libelf? Я сам не пробовал, так что это может оказаться кошмаром (и если вы никогда не делали Cython или ctypes, возможно, сейчас не лучшее время для обучения…), но, возможно, стоит задуматься. - person abarnert; 13.12.2012