2010-08-02 11 views
7

¿Cómo hacer esto en C#?Cargando un archivo en un mapa de bits pero dejando intacto el archivo original

Si uso Bitmap.FromFile(), el archivo original está bloqueado.

Si uso Bitmap.FromStream(), el archivo original no está bloqueado, pero la documentación dice "Debe mantener la secuencia abierta durante el tiempo de vida de la imagen". Esto probablemente significa que el archivo todavía está vinculado al objeto de imagen, (por ejemplo, quizás si el archivo cambia también lo hace el objeto o viceversa).

lo que quiero hacer es leer el mapa de bits y guardarlo en un objeto y después de eso no hay ninguna relación entre el archivo y el objeto Imagen

Respuesta

25

Información básica sobre este comportamiento: Bitmap utiliza un archivo mapeado en memoria para acceder a los píxeles en el mapa de bits. Esa es una facilidad muy básica en la API de Windows, permite un mapeo muy eficiente de la memoria a los datos de archivo. Los datos se leen del archivo solo cuando el programa lee la memoria, las páginas de memoria virtual no ocupan ningún espacio en el archivo de paginación de Windows.

El mismo mecanismo exacto se usa para cargar ensamblajes .NET. Es la asignación de memoria que pone un bloqueo en el archivo. Que es básicamente por qué los ensamblados están bloqueados cuando se usan en un programa .NET. El método Image.Dispose() libera el bloqueo. Combatir el bloqueo a menudo indica que te estás olvidando de tirar tus mapas de bits. Muy importante, olvidarse de llamar a Dispose() no suele causar problemas para las clases .NET, excepto para Bitmap, ya que puede necesitar tanta memoria (no administrada).

Sí, FromStream() impide que la clase realice esta optimización. El costo es significativo, necesitará el doble de memoria cuando se cargue el mapa de bits. Esto será un problema cuando el mapa de bits es grande, está bordeando OOM cuando el programa ha estado funcionando por un tiempo (fragmentando el espacio de direcciones) y no se está ejecutando en un sistema operativo de 64 bits. Definitivamente evite hacer esto si el ancho de mapa x Altura x 4> = 45 MB, más o menos.

Parte del código, usted no tiene que pasar por el aro CopyStream:

public static Image LoadImageNoLock(string path) { 
     var ms = new MemoryStream(File.ReadAllBytes(path)); // Don't use using!! 
     return Image.FromStream(ms); 
    } 

Tenga en cuenta que usted no desea deshacerse de la MemoryStream, podrás obtener una difícil de diagnosticar "error genérico" cuando el mapa de bits se usa si lo haces. Causado por la clase de imagen perezoso, leyendo la secuencia.

+0

También necesita esto para obtener el mapa de bits. Bitmap bitmap = new Bitmap (LoadImageNoLock (ruta)); – Harris

+2

MemoryStream es desechable, ¿quién se encargará de eliminarlo en esta solución? – kwesolowski

4

leer el archivo en la memoria copiándolo desde un FileStream en un MemoryStream. (Busque CopyStream en Stack Overflow para encontrar muchos ejemplos de cómo hacerlo de manera segura. Básicamente bucle mientras lee, escribiendo cada fragmento en la secuencia de memoria, hasta que no haya más datos para leer). A continuación, rebobine el MemoryStream (conjunto Position = 0) y luego pasa eso al Bitmap.FromStream.

4

Para crear una imagen sin bloquear el archivo, deberá crear una copia del archivo FileStream de la imagen. Consulte esta página Best way to copy between two Stream instances - C# para saber cómo copiar la secuencia.

A continuación, simplemente cree su imagen a partir de la secuencia copiada y estará listo para comenzar.

+0

+1 por hacer la búsqueda por nosotros que Jon sugirió que deberíamos hacer ... Encontraste una muy buena publicación para esto. – awe

0

He utilizado esta técnica de copia en MemoryStream y luego alimentar el MemoryStream a Bitmap.FromStream bastantes veces. Sin embargo, hay un gotcha con esta técnica también.

Si planea utilizar uno de los métodos Bitmap.Save más adelante en la imagen cargada, tendrá que mantener la secuencia activa (es decir, no lo elimine después de que se cargue la imagen), de lo contrario obtendrá la temida "excepción genérica GDI + error".

Cuestiones relacionadas