我正在循环遍历目录并复制所有文件。现在我正在做
string.EndsWith
检查 ".jpg"
或 ".png"
等。 .
有没有更优雅的方法来确定文件是否是图像(任何图像类型)而无需像上面那样进行黑客检查?
查看 System.IO.Path.GetExtension
这是一个快速示例。
public static readonly List<string> ImageExtensions = new List<string> { ".JPG", ".JPEG", ".JPE", ".BMP", ".GIF", ".PNG" };
private void button_Click(object sender, RoutedEventArgs e)
{
var folder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var files = Directory.GetFiles(folder);
foreach(var f in files)
{
if (ImageExtensions.Contains(Path.GetExtension(f).ToUpperInvariant()))
{
// process image
}
}
}
System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/");
MimeMapping.GetMimeMapping
产生以下结果:
file.svg 在大多数情况下不会返回图像/ MIME 类型,因为您可能不会像处理标量图像那样处理矢量图像。检查 MIME 类型时,请注意 SVG 确实具有 image/svg+xml 标准 MIME 类型,即使
GetMimeMapping
不返回它。
这将查看文件的前几个字节并确定它是否是图像。
using System.Collections.Generic;
using System.IO;
using System.Linq;
public static class Extension
{
public static bool IsImage(this Stream stream)
{
stream.Seek(0, SeekOrigin.Begin);
List<string> jpg = new List<string> { "FF", "D8" };
List<string> bmp = new List<string> { "42", "4D" };
List<string> gif = new List<string> { "47", "49", "46" };
List<string> png = new List<string> { "89", "50", "4E", "47", "0D", "0A", "1A", "0A" };
List<List<string>> imgTypes = new List<List<string>> { jpg, bmp, gif, png };
List<string> bytesIterated = new List<string>();
for (int i = 0; i < 8; i++)
{
string bit = stream.ReadByte().ToString("X2");
bytesIterated.Add(bit);
bool isImage = imgTypes.Any(img => !img.Except(bytesIterated).Any());
if (isImage)
{
return true;
}
}
return false;
}
}
我对上面的内容做了一些更改,以便您可以根据需要添加自己的图像,还删除了原本不需要的集合。我还添加了一个重载,接受
out
类型的 string
参数,将值设置为流组成的图像类型。
public static class Extension
{
static Extension()
{
ImageTypes = new Dictionary<string, string>();
ImageTypes.Add("FFD8","jpg");
ImageTypes.Add("424D","bmp");
ImageTypes.Add("474946","gif");
ImageTypes.Add("89504E470D0A1A0A","png");
}
/// <summary>
/// <para> Registers a hexadecimal value used for a given image type </para>
/// <param name="imageType"> The type of image, example: "png" </param>
/// <param name="uniqueHeaderAsHex"> The type of image, example: "89504E470D0A1A0A" </param>
/// </summary>
public static void RegisterImageHeaderSignature(string imageType, string uniqueHeaderAsHex)
{
Regex validator = new Regex(@"^[A-F0-9]+$", RegexOptions.CultureInvariant);
uniqueHeaderAsHex = uniqueHeaderAsHex.Replace(" ", "");
if (string.IsNullOrWhiteSpace(imageType)) throw new ArgumentNullException("imageType");
if (string.IsNullOrWhiteSpace(uniqueHeaderAsHex)) throw new ArgumentNullException("uniqueHeaderAsHex");
if (uniqueHeaderAsHex.Length % 2 != 0) throw new ArgumentException ("Hexadecimal value is invalid");
if (!validator.IsMatch(uniqueHeaderAsHex)) throw new ArgumentException ("Hexadecimal value is invalid");
ImageTypes.Add(uniqueHeaderAsHex, imageType);
}
private static Dictionary<string, string> ImageTypes;
public static bool IsImage(this Stream stream)
{
string imageType;
return stream.IsImage(out imageType);
}
public static bool IsImage(this Stream stream, out string imageType)
{
stream.Seek(0, SeekOrigin.Begin);
StringBuilder builder = new StringBuilder();
int largestByteHeader = ImageTypes.Max(img => img.Value.Length);
for (int i = 0; i < largestByteHeader; i++)
{
string bit = stream.ReadByte().ToString("X2");
builder.Append(bit);
string builtHex = builder.ToString();
bool isImage = ImageTypes.Keys.Any(img => img == builtHex);
if (isImage)
{
imageType = ImageTypes[builder.ToString()];
return true;
}
}
imageType = null;
return false;
}
}
如果您想在从文件中完全读取图像文件之前快速验证图像文件,除了比较文件扩展名之外,您还可以检查其标头以查找文件签名(以下代码
IsValidImageFile()
检查BMP,GIF87a 、GIF89a、PNG、TIFF、JPEG)
/// <summary>
/// Reads the header of different image formats
/// </summary>
/// <param name="file">Image file</param>
/// <returns>true if valid file signature (magic number/header marker) is found</returns>
private bool IsValidImageFile(string file)
{
byte[] buffer = new byte[8];
byte[] bufferEnd = new byte[2];
var bmp = new byte[] { 0x42, 0x4D }; // BMP "BM"
var gif87a = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }; // "GIF87a"
var gif89a = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }; // "GIF89a"
var png = new byte[] { 0x89, 0x50, 0x4e, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; // PNG "\x89PNG\x0D\0xA\0x1A\0x0A"
var tiffI = new byte[] { 0x49, 0x49, 0x2A, 0x00 }; // TIFF II "II\x2A\x00"
var tiffM = new byte[] { 0x4D, 0x4D, 0x00, 0x2A }; // TIFF MM "MM\x00\x2A"
var jpeg = new byte[] { 0xFF, 0xD8, 0xFF }; // JPEG JFIF (SOI "\xFF\xD8" and half next marker xFF)
var jpegEnd = new byte[] { 0xFF, 0xD9 }; // JPEG EOI "\xFF\xD9"
try
{
using (System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
if (fs.Length > buffer.Length)
{
fs.Read(buffer, 0, buffer.Length);
fs.Position = (int)fs.Length - bufferEnd.Length;
fs.Read(bufferEnd, 0, bufferEnd.Length);
}
fs.Close();
}
if (this.ByteArrayStartsWith(buffer, bmp) ||
this.ByteArrayStartsWith(buffer, gif87a) ||
this.ByteArrayStartsWith(buffer, gif89a) ||
this.ByteArrayStartsWith(buffer, png) ||
this.ByteArrayStartsWith(buffer, tiffI) ||
this.ByteArrayStartsWith(buffer, tiffM))
{
return true;
}
if (this.ByteArrayStartsWith(buffer, jpeg))
{
// Offset 0 (Two Bytes): JPEG SOI marker (FFD8 hex)
// Offest 1 (Two Bytes): Application segment (FF?? normally ??=E0)
// Trailer (Last Two Bytes): EOI marker FFD9 hex
if (this.ByteArrayStartsWith(bufferEnd, jpegEnd))
{
return true;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Lang.Lang.ErrorTitle + " IsValidImageFile()", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return false;
}
/// <summary>
/// Returns a value indicating whether a specified subarray occurs within array
/// </summary>
/// <param name="a">Main array</param>
/// <param name="b">Subarray to seek within main array</param>
/// <returns>true if a array starts with b subarray or if b is empty; otherwise false</returns>
private bool ByteArrayStartsWith(byte[] a, byte[] b)
{
if (a.Length < b.Length)
{
return false;
}
for (int i = 0; i < b.Length; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
检查标头签名可以很快,因为它不会加载整个文件或创建大对象,特别是在处理多个文件时。但它不会检查其余数据是否格式良好。为此,可以执行第二步尝试将文件加载到
Image
对象(这样可以确保该文件可以由您的程序显示和处理)。
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;
}
我们可以使用命名空间 System.Drawing 中的 Image 和图形类;做我们的工作。如果代码运行没有错误,则它是图像,否则不是。这就是让 DotNet 框架为我们完成这项工作。 代码 -
public string CheckFile(file)
{
string result="";
try
{
System.Drawing.Image imgInput = System.Drawing.Image.FromFile(file);
System.Drawing.Graphics gInput = System.Drawing.Graphics.fromimage(imgInput);
Imaging.ImageFormat thisFormat = imgInput.RawFormat;
result="It is image";
}
catch(Exception ex)
{
result="It is not image";
}
return result;
}
我使用以下方法。它使用内置的图像解码器来检索系统识别为图像文件的扩展名列表,然后将这些扩展名与您传入的文件名的扩展名进行比较。返回一个简单的 TRUE/FALSE。
public static bool IsRecognisedImageFile(string fileName)
{
string targetExtension = System.IO.Path.GetExtension(fileName);
if (String.IsNullOrEmpty(targetExtension))
return false;
else
targetExtension = "*" + targetExtension.ToLowerInvariant();
List<string> recognisedImageExtensions = new List<string>();
foreach (System.Drawing.Imaging.ImageCodecInfo imageCodec in System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders())
recognisedImageExtensions.AddRange(imageCodec.FilenameExtension.ToLowerInvariant().Split(";".ToCharArray()));
foreach (string extension in recognisedImageExtensions)
{
if (extension.Equals(targetExtension))
{
return true;
}
}
return false;
}
看看这个是否有帮助。
编辑:另外,Image.FromFile(....).RawFormat 可能会有所帮助。如果文件不是图像,它可能会抛出异常。
不完全是您需要的答案。但如果是互联网,则输入MIME。
我不确定这个解决方案的性能缺点是什么,但是您不能在 try 块中对文件执行一些图像函数吗?如果它不是图像,该函数会失败并落入 catch 块?
此策略可能并非在所有情况下都是最佳解决方案,但就我目前正在使用的情况而言,它有一个主要优点: 您可以使用计划用于处理图像(如果是图像)的任何函数来进行测试函数。通过这种方式,您可以测试所有当前的图像类型,但它也可以扩展到未来的图像类型,而无需将新的图像扩展添加到支持的图像类型列表中。
有人看到这个策略有什么缺点吗?
这是一个棘手的问题。如果文件不是图像,则会抛出异常。由此我们可以检查文件是否为图像。
using (Stream stream = File.OpenRead(file))
{
try
{
using (Image sourceImage = Image.FromStream(stream, false, false))
{
}
}
catch (Exception x)
{
if (x.Message.Contains("not valid"))
{
Console.Write("This is not a Image.");
}
}
}
这就是我使用的 - 它只是@dylmcc 答案的一个调整,以使其更具可读性。
public static bool IsRecognisedImageFile(string fileName)
{
string targetExtension = System.IO.Path.GetExtension(fileName);
if (String.IsNullOrEmpty(targetExtension))
{
return false;
}
var recognisedImageExtensions = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders().SelectMany(codec => codec.FilenameExtension.ToLowerInvariant().Split(';'));
targetExtension = "*" + targetExtension.ToLowerInvariant();
return recognisedImageExtensions.Contains(targetExtension);
}
首先您应该检查文件 mime 类型,然后检查它是否包含
image/
,这是 Asp.net core 中最简单的方法
public bool? CheckFileIsImage(string? fileName)
{
var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
provider.TryGetContentType(fileName, out string? contentType);
return contentType?.Contains("image/") ?? false;
}
我的简单代码
public static List<string> GetAllPhotosExtensions()
{
var list = new List<string>();
list.Add(".jpg");
list.Add(".png");
list.Add(".bmp");
list.Add(".gif");
list.Add(".jpeg");
list.Add(".tiff");
return list;
}
检查是否有图像文件
public static bool IsPhoto(string fileName)
{
var list = FileListExtensions.GetAllPhotosExtensions();
var filename= fileName.ToLower();
bool isThere = false;
foreach(var item in list)
{
if (filename.EndsWith(item))
{
isThere = true;
break;
}
}
return isThere;
}