2012-05-08 11 views
19

Recojo imágenes con open-uri desde un sitio web remoto y las conservo en mi servidor local dentro de mi aplicación Ruby on Rails. La mayoría de las imágenes se mostraron sin problemas, pero algunas imágenes simplemente no aparecieron.¿Por qué OpenURI trata los archivos de menos de 10kb como StringIO?

Después de una larga sesión de depuración a fin descubrí (gracias a this blogpost) que la razón de esto es que el class Buffer en los archivos open-uri-libary trata con menos de 10 kb de tamaño a medida IO-objetos en lugar de TEMPFILES.

me las arreglé para conseguir alrededor de este problema siguiendo la respuesta de Miqueas Winkelspecht a this StackOverflow question, donde pongo el siguiente código dentro de un archivo en mis inicializadores:

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 

Esto funciona como se esperaba hasta ahora, pero yo sigan preguntándose, ¿por qué pusieron este código en la biblioteca en primer lugar? ¿Alguien sabe un motivo específico, por qué los archivos de menos de 10kb se tratan como StringIO?

Dado que el código anterior prácticamente restablece este comportamiento globalmente para toda mi aplicación, solo quiero asegurarme de no romper nada más.

Respuesta

12

Cuando uno realiza programación de red, asigna un búfer de un tamaño razonablemente grande y envía y lee unidades de datos que caben en el búfer. Sin embargo, al tratar con archivos (o a veces cosas llamadas BLOB) no puede suponer que los datos se ajustarán a su búfer. Por lo tanto, necesita un manejo especial para estas grandes corrientes de datos.

(A veces las unidades de datos que se ajustan al búfer se llaman paquetes. Sin embargo, los paquetes son realmente algo de la capa 4, como los marcos en la capa 2. Como esto sucede una capa 7, se les podría llamar mensajes .)

Para respuestas mayores a 10K, la biblioteca open-uri está configurando la sobrecarga adicional para escribir en un flujo de objetos. Cuando está bajo el tamaño de StringMax, solo incluye la cadena en el mensaje, ya que sabe que puede caber en el búfer.

+0

gracias, buena explicación – klaffenboeck

+3

No del todo correcto. La cadena que se usa como buffer en este caso no tiene un tamaño fijo; las cadenas en Ruby se cambian de tamaño dinámicamente. De hecho, puede cambiar el tamaño de los búferes de forma dinámica en la mayoría de los idiomas (aunque no siempre de forma automática). Sospecho que la verdadera razón para usar StringIO para archivos pequeños es una compensación de uso de rendimiento/memoria. – pelle

+2

True @pelle. Tomando nota de que dijiste que no del todo. En el caso de los BLOB, * cualquier * suposición sobre el ajuste podría romperse con un BLOB aún mayor. Eso incluye lo que no cabe en la memoria. En algún punto, el manejo de flujos requiere transmisión, y la clase Buffer está eligiendo 10K como el punto de inflexión para simplemente abandonar y manejar el archivo mediante transmisión. –

Cuestiones relacionadas