检测没有扩展名的文件是否为图像
Detect if a file with no extension is an image
我正在尝试确定没有扩展名的文件是否是图像,但似乎无法正确处理。我知道它绝对是一张图片,因为我可以在 MS Paint 中打开它。无论如何,这是我的代码
private bool IsImage(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)
{
textBox1.Text = "is image";
return true;
}
}
textBox1.Text = "is not image";
return false;
}
private void button1_Click(object sender, EventArgs e)
{
string filepath = @"C:\Users\William\Documents\drivers";
MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(filepath));
IsImage(mStrm);
}
也忽略它在一个名为 drivers 的文件中,该文件不是驱动程序或任何东西
像这样使用 FileStream 而不是 MemoryStream:
private void button1_Click(object sender, EventArgs e)
{
string filepath = @"C:\Users\William\Documents\drivers";
var mStrm = new FileStream(filepath , FileMode.Open, FileAccess.Read)
IsImage(mStrm);
}
希望对您有所帮助
如果您尝试比较 header 中的字节序列,比较 byte[]
似乎比 string
更好。
// simple class to associate a signature with a name
public class ImgHeader
{
public readonly string Name;
public readonly byte[] Header;
public static readonly ImgHeader GIF89a = new ImgHeader("GIF89a", new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 });
public static readonly ImgHeader GIF87a = new ImgHeader("GIF87a", new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 });
public static readonly ImgHeader JPG = new ImgHeader("JPG", new byte[]{0xFF, 0xD8});
public static readonly ImgHeader PNG = new ImgHeader("PNG", new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A });
private ImgHeader(string n, byte[] h)
{
this.Name = n;
this.Header = h;
}
}
然后,collection 个(请注意,列表可以更长,BMP、TIFF 等):
List<ImgHeader> imgSigs = new List<ImgHeader>();
imgSigs.Add(ImgHeader.GIF87a);
imgSigs.Add(ImgHeader.GIF89a);
imgSigs.Add(ImgHeader.JPG);
imgSigs.Add(ImgHeader.PNG);
给定一个 List<string>
表示完整的文件名,迭代并比较 header 个字节:
foreach (string s in files)
{
using (FileStream fs = new FileStream(s,FileMode.Open, FileAccess.Read))
using (BinaryReader br = new BinaryReader(fs))
{
//max header size
byte[] hdr = br.ReadBytes(8);
foreach (ImgHeader sig in imgSigs)
{
// subset of bytes read for comparison
byte[] testHdr = new byte[sig.Header.Length];
Array.Copy(hdr, testHdr, sig.Header.Length);
//if( CompareBytes(hdr, sig.Header))
if (testHdr.SequenceEqual(sig.Header))
{
Console.WriteLine("{0} is {1}", s, sig.Name);
break;
}
}
}
}
与其创建临时数组并复制以使用 SequenceEqual
,不如调用比较器方法更快,该方法使用 for n
循环来仅测试与给定签名中一样多的字节大批。
实际上,使用秒表没有足够的差异需要担心。仅当您有数千个文件要处理时才重要。
我正在尝试确定没有扩展名的文件是否是图像,但似乎无法正确处理。我知道它绝对是一张图片,因为我可以在 MS Paint 中打开它。无论如何,这是我的代码
private bool IsImage(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)
{
textBox1.Text = "is image";
return true;
}
}
textBox1.Text = "is not image";
return false;
}
private void button1_Click(object sender, EventArgs e)
{
string filepath = @"C:\Users\William\Documents\drivers";
MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(filepath));
IsImage(mStrm);
}
也忽略它在一个名为 drivers 的文件中,该文件不是驱动程序或任何东西
像这样使用 FileStream 而不是 MemoryStream:
private void button1_Click(object sender, EventArgs e)
{
string filepath = @"C:\Users\William\Documents\drivers";
var mStrm = new FileStream(filepath , FileMode.Open, FileAccess.Read)
IsImage(mStrm);
}
希望对您有所帮助
如果您尝试比较 header 中的字节序列,比较 byte[]
似乎比 string
更好。
// simple class to associate a signature with a name
public class ImgHeader
{
public readonly string Name;
public readonly byte[] Header;
public static readonly ImgHeader GIF89a = new ImgHeader("GIF89a", new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 });
public static readonly ImgHeader GIF87a = new ImgHeader("GIF87a", new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 });
public static readonly ImgHeader JPG = new ImgHeader("JPG", new byte[]{0xFF, 0xD8});
public static readonly ImgHeader PNG = new ImgHeader("PNG", new byte[] {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A });
private ImgHeader(string n, byte[] h)
{
this.Name = n;
this.Header = h;
}
}
然后,collection 个(请注意,列表可以更长,BMP、TIFF 等):
List<ImgHeader> imgSigs = new List<ImgHeader>();
imgSigs.Add(ImgHeader.GIF87a);
imgSigs.Add(ImgHeader.GIF89a);
imgSigs.Add(ImgHeader.JPG);
imgSigs.Add(ImgHeader.PNG);
给定一个 List<string>
表示完整的文件名,迭代并比较 header 个字节:
foreach (string s in files)
{
using (FileStream fs = new FileStream(s,FileMode.Open, FileAccess.Read))
using (BinaryReader br = new BinaryReader(fs))
{
//max header size
byte[] hdr = br.ReadBytes(8);
foreach (ImgHeader sig in imgSigs)
{
// subset of bytes read for comparison
byte[] testHdr = new byte[sig.Header.Length];
Array.Copy(hdr, testHdr, sig.Header.Length);
//if( CompareBytes(hdr, sig.Header))
if (testHdr.SequenceEqual(sig.Header))
{
Console.WriteLine("{0} is {1}", s, sig.Name);
break;
}
}
}
}
与其创建临时数组并复制以使用 SequenceEqual
,不如调用比较器方法更快,该方法使用 for n
循环来仅测试与给定签名中一样多的字节大批。
实际上,使用秒表没有足够的差异需要担心。仅当您有数千个文件要处理时才重要。