gdi+ - ¿Por qué Image.FromFile mantiene un manejador de archivo abierto algunas veces?
filehandle (8)
Acabo de encontrar el mismo problema, cuando intentaba fusionar múltiples archivos TIFF de una sola página en una imagen TIFF multiparte. Necesitaba usar Image.Save()
y ''Image.SaveAdd () `: https://msdn.microsoft.com/en-us/library/windows/desktop/ms533839%28v=vs.85%29.aspx
La solución en mi caso era llamar ".Dispose ()" para cada una de las imágenes, tan pronto como terminé con ellas:
'' Iterate through each single-page source .tiff file
Dim initialTiff As System.Drawing.Image = Nothing
For Each filePath As String In srcFilePaths
Using fs As System.IO.FileStream = File.Open(filePath, FileMode.Open, FileAccess.Read)
If initialTiff Is Nothing Then
'' ... Save 1st page of multi-part .TIFF
initialTiff = Image.FromStream(fs)
encoderParams.Param(0) = New EncoderParameter(Encoder.Compression, EncoderValue.CompressionCCITT4)
encoderParams.Param(1) = New EncoderParameter(Encoder.SaveFlag, EncoderValue.MultiFrame)
initialTiff.Save(outputFilePath, encoderInfo, encoderParams)
Else
'' ... Save subsequent pages
Dim newTiff As System.Drawing.Image = Image.FromStream(fs)
encoderParams = New EncoderParameters(2)
encoderParams.Param(0) = New EncoderParameter(Encoder.Compression, EncoderValue.CompressionCCITT4)
encoderParams.Param(1) = New EncoderParameter(Encoder.SaveFlag, EncoderValue.FrameDimensionPage)
initialTiff.SaveAdd(newTiff, encoderParams)
newTiff.Dispose()
End If
End Using
Next
'' Make sure to close the file
initialTiff.Dispose()
Estoy haciendo un montón de procesamiento de imágenes en GDI + en .NET en una aplicación ASP.NET.
Con frecuencia encuentro que Image.FromFile () mantiene abierto el manejador de archivo.
¿Por qué es esto? ¿Cuál es la mejor manera de abrir una imagen sin que se retenga el identificador de archivo?
- NB: No estoy haciendo nada estúpido como mantener el objeto Image por ahí, e incluso si lo fuera, no esperaría que el manejador del archivo se mantuviera activo.
Asegúrate de que estás desechando correctamente.
using (Image.FromFile("path")) {}
La expresión de uso es una abreviatura de
IDisposable obj;
try { }
finally
{
obj.Dispose();
}
@Rex en el caso de Image.Dispose llama a GdipDisposeImage extern / native Win32 call en su Dispose ().
IDisposable se usa como un mecanismo para liberar recursos no administrados (Qué manejadores de archivo son)
Como se mencionó anteriormente, el funcionamiento de Microsoft causa un error GDI + después de que se hayan cargado varias imágenes. La solución de VB para mí como se mencionó anteriormente por Steven es
picTemp.Image = Image.FromStream(New System.IO.MemoryStream(My.Computer.FileSystem.ReadAllBytes(strFl)))
He tenido el mismo problema y he recurrido a leer el archivo usando
return Image.FromStream(new MemoryStream(File.ReadAllBytes(fileName)));
Hice el mismo recorrido que algunos otros carteles en este hilo. Cosas que noté:
El uso de Image.FromFile parece impredecible cuando se libera el identificador del archivo. Al llamar a Image.Dispose () no se soltó el identificador del archivo en todos los casos.
El uso de FileStream y el método Image.FromStream funciona, y libera el control en el archivo si llama a Dispose () en FileStream o lo envuelve todo en una instrucción Using {} como lo recomienda Kris. Sin embargo, si intenta guardar el objeto Image en una secuencia, el método Image.Save arroja una excepción "Se produjo un error genérico en GDI +" . Presumiblemente, algo en el método Save quiere saber sobre el archivo de origen.
El enfoque de Steven funcionó para mí. Pude borrar el archivo de origen con el objeto Imagen en la memoria. También pude guardar la imagen tanto en una secuencia como en un archivo (necesitaba hacer ambas cosas). También pude guardar en un archivo con el mismo nombre que el archivo de origen, algo que está documentado como no posible si usas el método Image.FromFile (esto me parece extraño, ya que seguramente este es el caso de uso más probable, pero oye .)
Para resumir, abra su Imagen de esta manera:
Image img = Image.FromStream(new MemoryStream(File.ReadAllBytes(path)));
Entonces puede manipularlo (y el archivo de origen) como mejor le parezca.
Image.FromFile mantiene el manejador de archivo abierto hasta que se elimina la imagen. Desde MSDN :
"El archivo permanece bloqueado hasta que se elimine la imagen".
Use Image.FromStream, y no tendrá el problema.
using(var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
return Image.FromStream(fs);
}
Editar: (un año y un poco más tarde)
El código anterior es peligroso, ya que es impredecible, en algún momento (después de cerrar la cadena de archivos) puede aparecer el temido "Se produjo un error genérico en GDI +" . Lo enmendaría a:
Image tmpImage;
Bitmap returnImage;
using(var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
tmpImage = Image.FromStream(fs);
returnImage = new Bitmap(tmpImage);
tmpImage.Dispose();
}
return returnImage;
También probé todas tus sugerencias (ReadAllBytes, FileStream => FromStream => newBitmap () para hacer una copia, etc.) y todas funcionaron. Sin embargo, me preguntaba si podrías encontrar algo más corto y
using (Image temp = Image.FromFile(path))
{
return new Bitmap(temp);
}
parece funcionar también, ya que dispone el identificador del archivo así como el Objeto-imagen original y crea un nuevo objeto Bitmap, que es independiente del archivo original y, por lo tanto, puede guardarse en una secuencia o archivo sin errores.
Tendría que señalar con el dedo al Recolector de Basura. Dejarlo no es realmente el problema si está a merced de Garbage Collection.
Este tipo tenía una complaint similar ... y encontró una forma de utilizar un objeto FileStream en lugar de cargarlo directamente desde el archivo.
public static Image LoadImageFromFile(string fileName)
{
Image theImage = null;
fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
{
byte[] img;
img = new byte[fileStream.Length];
fileStream.Read(img, 0, img.Length);
fileStream.Close();
theImage = Image.FromStream(new MemoryStream(img));
img = null;
}
...
Parece un truco completo ...