Почему OpenURI обрабатывает файлы размером менее 10 КБ как StringIO?

Я получаю изображения с помощью open-uri с удаленного веб-сайта и сохраняю их на своем локальном сервере в своем приложении Ruby on Rails. Большинство изображений показывались без проблем, но некоторые изображения просто не отображались.

После очень долгого сеанса отладки я наконец узнал (спасибо это сообщение в блоге), что причина этого в том, что class Buffer в open-uri-libary обрабатывает файлы размером менее 10 КБ как объекты ввода-вывода, а не временные файлы.

Мне удалось обойти эту проблему, следуя ответу Мики Винкельспехта на этот вопрос StackOverflow, где я поместил следующий код в файл в моих инициализаторах:

require 'open-uri'
# Don't allow downloaded files to be created as StringIO. Force a tempfile to be created.
OpenURI::Buffer.send :remove_const, 'StringMax' if OpenURI::Buffer.const_defined?('StringMax')
OpenURI::Buffer.const_set 'StringMax', 0

Пока это работает так, как ожидалось, но мне все время интересно, почему они вообще поместили этот код в библиотеку? Кто-нибудь знает конкретную причину, почему файлы размером менее 10 КБ обрабатываются как StringIO?

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


person klaffenboeck    schedule 08.05.2012    source источник


Ответы (1)


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

(Иногда единицы данных, помещающиеся в буфер, называются пакетами. Однако на самом деле пакеты относятся к уровню 4, как и кадры к уровню 2. Поскольку это происходит на уровне 7, их лучше называть сообщениями.)

Для ответов размером более 10 КБ библиотека open-uri настраивает дополнительные служебные данные для записи в объекты потока. При размере меньше StringMax он просто включает строку в сообщение, поскольку знает, что она может поместиться в буфере.

person Marlin Pierce    schedule 08.05.2012
comment
Не совсем правильно. Строка, которая используется в качестве буфера в этом случае, не имеет фиксированного размера; строки в Ruby динамически изменяются. Действительно, в большинстве языков вы можете динамически изменять размер буферов (хотя и не всегда автоматически). Я подозреваю, что настоящей причиной использования StringIO для небольших файлов является компромисс между производительностью и использованием памяти. - person pelle; 13.01.2014
comment
Правда @pelle. Отметив, что вы сказали не совсем так. В случае BLOB любое предположение о подгонке может быть нарушено еще большим BLOB. Это включает в себя то, что не умещается в памяти. В какой-то момент обработка потоков требует потоковой передачи, и класс Buffer выбирает 10 КБ в качестве переломного момента, чтобы просто сдаться и обрабатывать файл потоковой передачей. - person Marlin Pierce; 31.01.2014