validar una txt saber nombre existe example eliminar crear convert carpeta buscar archivo and c# .net image file-io

una - validar nombre de archivo c#



Validar imagen desde archivo en C# (12)

Estoy cargando una imagen de un archivo, y quiero saber cómo validar la imagen antes de que se lea completamente desde el archivo.

string filePath = "image.jpg"; Image newImage = Image.FromFile(filePath);

El problema ocurre cuando image.jpg no es realmente un jpg. Por ejemplo, si creo un archivo de texto vacío y lo cambio a image.jpg, se lanzará una excepción OutOfMemory cuando se cargue image.jpg.

Estoy buscando una función que valide una imagen dada una secuencia o una ruta de archivo de la imagen.

Ejemplo de función prototipo

bool IsValidImage(string fileName); bool IsValidImage(Stream imageStream);


Bueno, seguí y codifiqué una serie de funciones para resolver el problema. Primero verifica el encabezado y luego intenta cargar la imagen en un bloque try / catch. Solo comprueba si hay archivos GIF, BMP, JPG y PNG. Puede agregar fácilmente más tipos agregando un encabezado a imageHeaders.

static bool IsValidImage(string filePath) { return File.Exists(filePath) && IsValidImage(new FileStream(filePath, FileMode.Open, FileAccess.Read)); } static bool IsValidImage(Stream imageStream) { if(imageStream.Length > 0) { byte[] header = new byte[4]; // Change size if needed. string[] imageHeaders = new[]{ "/xFF/xD8", // JPEG "BM", // BMP "GIF", // GIF Encoding.ASCII.GetString(new byte[]{137, 80, 78, 71})}; // PNG imageStream.Read(header, 0, header.Length); bool isImageHeader = imageHeaders.Count(str => Encoding.ASCII.GetString(header).StartsWith(str)) > 0; if (isImageHeader == true) { try { Image.FromStream(imageStream).Dispose(); imageStream.Close(); return true; } catch { } } } imageStream.Close(); return false; }


Crearía un método como:

Image openImage(string filename);

en el que manejo la excepción Si el valor devuelto es nulo, hay un nombre / tipo de archivo no válido.


Esto debería ser el truco: no tiene que leer los bytes sin procesar fuera del encabezado:

using(Image test = Image.FromFile(filePath)) { bool isJpeg = (test.RawFormat.Equals(ImageFormat.Jpeg)); }

Por supuesto, también debe atrapar OutOfMemoryException, que lo salvará si el archivo no es una imagen en absoluto.

Y, ImageFormat tiene elementos preestablecidos para todos los otros tipos de imágenes principales que admite GDI +.

Tenga en cuenta que debe usar .Equals () y no == en objetos ImageFormat (no es una enumeración) porque el operador == no está sobrecargado para llamar al método Equals.


Los archivos JPEG no tienen una definición formal de encabezado, pero tienen una pequeña cantidad de metadatos que puede usar.

  • Offset 0 (dos bytes): marcador JPEG SOI (hex FFD8)
  • Offset 2 (Two Bytes): ancho de la imagen en píxeles
  • Compensación 4 (dos bytes): altura de la imagen en píxeles
  • Offset 6 (Byte): Número de componentes (1 = escala de grises, 3 = RGB)

Hay un par de otras cosas después de eso, pero esas no son importantes.

Puede abrir el archivo usando una secuencia binaria y leer estos datos iniciales, y asegurarse de que OffSet 0 sea 0 y OffSet 6 sea 1,2 o 3.

Eso al menos te daría un poco más de precisión.

O puedes atrapar la excepción y seguir, pero pensé que querías un desafío :)


Noté un par de problemas con todas las funciones anteriores. En primer lugar, Image.FromFile abre la imagen dada y luego causará un error de archivo abierto a quien quiera abrir el archivo de imagen dado por cualquier razón. Incluso la aplicación en sí misma, así que cambié usando Image.FromStream.

Después de cambiar los cambios de tipo api - exception de OutOfMemoryException a ArgumentException, por algún motivo poco claro para mí. (Probablemente el error de .net framework?)

Además, si .net agregará más formatos de archivo de imagen que actualmente, comprobaremos por función (tiene sentido primero intentar cargar la imagen si solo falla), solo después de eso para informar el error.

Entonces mi código se ve así:

try { using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { Image im = Image.FromStream(stream); // Do something with image if needed. } } catch (ArgumentException) { if( !IsValidImageFormat(path) ) return SetLastError("File ''" + fileName + "'' is not a valid image"); throw; }

Dónde:

/// <summary> /// Check if we have valid Image file format. /// </summary> /// <param name="path"></param> /// <returns>true if it''s image file</returns> public static bool IsValidImageFormat( String path ) { using ( FileStream fs = File.OpenRead(path) ) { byte[] header = new byte[10]; fs.Read(header, 0, 10); foreach ( var pattern in new byte[][] { Encoding.ASCII.GetBytes("BM"), Encoding.ASCII.GetBytes("GIF"), new byte[] { 137, 80, 78, 71 }, // PNG new byte[] { 73, 73, 42 }, // TIFF new byte[] { 77, 77, 42 }, // TIFF new byte[] { 255, 216, 255, 224 }, // jpeg new byte[] { 255, 216, 255, 225 } // jpeg canon } ) { if (pattern.SequenceEqual(header.Take(pattern.Length))) return true; } } return false; } //IsValidImageFormat


Puede hacer una tipificación aproximada olfateando el encabezado.

Esto significa que cada formato de archivo que implemente necesitará tener un encabezado identificable ...

JPEG: los primeros 4 bytes son FF D8 FF E0 (de hecho, solo los primeros dos bytes lo harían para jpeg no jfif, más información here ).

GIF: los primeros 6 bytes son "GIF87a" o "GIF89a" (más información here )

PNG: los primeros 8 bytes son: 89 50 4E 47 0D 0A 1A 0A (más información here )

TIFF: los primeros 4 bytes son: II42 o MM42 (más información here )

etc ... puede encontrar información de encabezado / formato para casi cualquier formato de gráficos que le interese y agregar a las cosas que maneja según sea necesario. Lo que no hará, es decirle si el archivo es una versión válida de ese tipo, pero le dará una pista sobre "imagen, no imagen". Todavía podría ser una imagen corrupta o incompleta y, por lo tanto, fallar cuando se abra, por lo que todavía es necesario intentar capturar la llamada .FromFile.


Puede leer los primeros bytes del Stream y compararlos con los bytes del encabezado mágico para JPEG.


Tomé la respuesta de Semicolon y la convertí a VB:

Private Function IsValidImage(imageStream As System.IO.Stream) As Boolean If (imageStream.Length = 0) Then isvalidimage = False Exit Function End If Dim pngByte() As Byte = New Byte() {137, 80, 78, 71} Dim pngHeader As String = System.Text.Encoding.ASCII.GetString(pngByte) Dim jpgByte() As Byte = New Byte() {255, 216} Dim jpgHeader As String = System.Text.Encoding.ASCII.GetString(jpgByte) Dim bmpHeader As String = "BM" Dim gifHeader As String = "GIF" Dim header(3) As Byte Dim imageHeaders As String() = New String() {jpgHeader, bmpHeader, gifHeader, pngHeader} imageStream.Read(header, 0, header.Length) Dim isImageHeader As Boolean = imageHeaders.Count(Function(str) System.Text.Encoding.ASCII.GetString(header).StartsWith(str)) > 0 If (isImageHeader) Then Try System.Drawing.Image.FromStream(imageStream).Dispose() imageStream.Close() IsValidImage = True Exit Function Catch ex As Exception System.Diagnostics.Debug.WriteLine("Not an image") End Try Else System.Diagnostics.Debug.WriteLine("Not an image") End If imageStream.Close() IsValidImage = False End Function


Un método que admite Tiff y Jpeg también

private bool IsValidImage(string filename) { Stream imageStream = null; try { imageStream = new FileStream(filename, FileMode.Open); if (imageStream.Length > 0) { byte[] header = new byte[30]; // Change size if needed. string[] imageHeaders = new[] { "BM", // BMP "GIF", // GIF Encoding.ASCII.GetString(new byte[]{137, 80, 78, 71}),// PNG "MM/x00/x2a", // TIFF "II/x2a/x00" // TIFF }; imageStream.Read(header, 0, header.Length); bool isImageHeader = imageHeaders.Count(str => Encoding.ASCII.GetString(header).StartsWith(str)) > 0; if (imageStream != null) { imageStream.Close(); imageStream.Dispose(); imageStream = null; } if (isImageHeader == false) { //Verify if is jpeg using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open))) { UInt16 soi = br.ReadUInt16(); // Start of Image (SOI) marker (FFD8) UInt16 jfif = br.ReadUInt16(); // JFIF marker return soi == 0xd8ff && (jfif == 0xe0ff || jfif == 57855); } } return isImageHeader; } return false; } catch { return false; } finally { if (imageStream != null) { imageStream.Close(); imageStream.Dispose(); } } }


aquí está mi imagen de verificación. No puedo confiar en las extensiones de archivos y tengo que verificar el formato por mi cuenta. Estoy cargando BitmapImages en WPF desde matrices de bytes y no conozco el formato por adelantado. WPF detecta el formato fino pero no le dice el formato de imagen de los objetos BitmapImage (al menos no conozco una propiedad para esto). Y no quiero cargar la imagen nuevamente con System.Drawing solo para detectar el formato. Esta solución es rápida y funciona bien para mí.

public enum ImageFormat { bmp, jpeg, gif, tiff, png, unknown } public static ImageFormat GetImageFormat(byte[] bytes) { // see http://www.mikekunz.com/image_file_header.html var bmp = Encoding.ASCII.GetBytes("BM"); // BMP var gif = Encoding.ASCII.GetBytes("GIF"); // GIF var png = new byte[] { 137, 80, 78, 71 }; // PNG var tiff = new byte[] { 73, 73, 42 }; // TIFF var tiff2 = new byte[] { 77, 77, 42 }; // TIFF var jpeg = new byte[] { 255, 216, 255, 224 }; // jpeg var jpeg2 = new byte[] { 255, 216, 255, 225 }; // jpeg canon if (bmp.SequenceEqual(bytes.Take(bmp.Length))) return ImageFormat.bmp; if (gif.SequenceEqual(bytes.Take(gif.Length))) return ImageFormat.gif; if (png.SequenceEqual(bytes.Take(png.Length))) return ImageFormat.png; if (tiff.SequenceEqual(bytes.Take(tiff.Length))) return ImageFormat.tiff; if (tiff2.SequenceEqual(bytes.Take(tiff2.Length))) return ImageFormat.tiff; if (jpeg.SequenceEqual(bytes.Take(jpeg.Length))) return ImageFormat.jpeg; if (jpeg2.SequenceEqual(bytes.Take(jpeg2.Length))) return ImageFormat.jpeg; return ImageFormat.unknown; }


en caso de que necesite la lectura de datos para otras operaciones y / o para otros tipos de archivos (PSD, por ejemplo), más adelante, el uso de la función Image.FromStream no es necesariamente una buena idea.


Utilizando Windows Forms:

bool IsValidImage(string filename) { try { using(Image newImage = Image.FromFile(filename)) {} } catch (OutOfMemoryException ex) { //The file does not have a valid image format. //-or- GDI+ does not support the pixel format of the file return false; } return true; }

De lo contrario, si está utilizando WPF puede hacer lo siguiente:

bool IsValidImage(string filename) { try { using(BitmapImage newImage = new BitmapImage(filename)) {} } catch(NotSupportedException) { // System.NotSupportedException: // No imaging component suitable to complete this operation was found. return false; } return true; }

Debes liberar la imagen creada. De lo contrario, cuando llame a esta función un gran número de veces, esto arrojaría OutOfMemoryException porque el sistema se quedó sin recursos, y no porque la imagen esté corrupta, arrojando un resultado incorrecto, y si elimina imágenes después de este paso, posiblemente estaría eliminando Buenos.