https://www.garykessler.net/library/file_sigs.html(Ctrl + F,然后输入 VHD)
看来VHD文件的前8个字节如下:63 6F 6E 65 63 74 69 78(conectix in ASCII.)
正如@jdweng 在 cmets 部分中所建议的,您也许可以使用BinaryReader 读取前 8 个字节,并将其与上面的值进行比较以确定文件是否为 VHD 文件。 s>
编辑:不起作用,正在寻找其他解决方案。
编辑2:实际上文件中似乎确实存在文本conectix,但它不在文件的开头;文本位于[the end of the file] - 0x200'th 字节。现在要去测试了。仅供参考,该文件是使用 Windows 10 上的磁盘管理工具生成的。
编辑 3:
private static bool IsVhd(string path)
{
byte[] vhdHeader = { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
byte[] header;
FileInfo file = new FileInfo(path);
long length = file.Length;
using (BinaryReader br = new BinaryReader(file.OpenRead()))
{
br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
header = br.ReadBytes(8);
}
return vhdHeader.SequenceEqual(header);
}
我相信这样就可以了。
编辑 4:
private static bool IsVhd(string path)
{
Span<byte> vhdHeader = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
Span<byte> header = stackalloc byte[8];
FileInfo file = new FileInfo(path);
long length = file.Length;
using (BinaryReader br = new BinaryReader(file.OpenRead()))
{
br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
br.Read(header);
}
return vhdHeader.SequenceEqual(header);
}
非分配较少的版本,以防您使用 .NET Core。 (需要 C# 7.3)
编辑 5:
private static bool IsVhd(string path)
{
Span<byte> vhdHeader = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
Span<byte> header = stackalloc byte[8];
FileInfo file = new FileInfo(path);
long length = file.Length;
using (BinaryReader br = new BinaryReader(file.OpenRead()))
{
br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
for (int i = 0; i < 8; i++)
header[i] = br.ReadByte();
}
return vhdHeader.SequenceEqual(header);
}
相同,但适用于 .NET Frameworks(由于优化,理想版本为 4.7.1;还需要 System.Memory NuGet 包。C# 7.3)
编辑 6:
According to the specs,似乎“硬盘页脚”位于最后 512(如果在 MS Virtual PC 2004 之前创建,则为 511)字节。
Note: Versions previous to Microsoft Virtual PC 2004 create disk images that have a 511-byte disk footer. So the hard disk footer can exist in the last 511 or 512 bytes of the file that holds the hard disk image.
Hard Disk Footer Field Descriptions
The following provides detailed definitions of the hard disk footer fields.
Cookie
Cookies are used to uniquely identify the original creator of the hard disk image. The values are case-sensitive.
Microsoft uses the “conectix” string to identify this file as a hard disk image created by Microsoft Virtual Server, Virtual PC, and predecessor products. The cookie is stored as an eight-character ASCII string with the “c” in the first byte, the “o” in the second byte, and so on.
如果文件大小小于 512 字节,我之前编写的代码将不起作用。我修复了它,因此它现在也可以处理具有 511 字节页脚的文件。另外,我添加了一些 cmets 来帮助维护。
/// <summary>
/// Determines whether the file indicated by the given path is a valid Virtual Hard Disk (.vhd) file.
/// </summary>
/// <param name="path">The path to the .vhd file to check.</param>
/// <returns>Whether the file is a valid vhd file or not.</returns>
//https://www.microsoft.com/en-us/download/details.aspx?id=23850
//See 'Hard Disk Footer Format'
//ASCII string "conectix" (63 6F 6E 65 63 74 69 78) is stored at the last 512 (511 if created on legacy platforms) bytes of the file
private static bool IsVhd(string path)
{
if (path is null) throw new ArgumentNullException(nameof(path));
Span<byte> vhdFooterCookie = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
Span<byte> cookie = stackalloc byte[9];
FileInfo file = new FileInfo(path);
long length = file.Length;
if (length < 511) return false; //Cannot be smaller than 512 bytes
using (BinaryReader br = new BinaryReader(file.OpenRead()))
{
br.BaseStream.Position = length - 0x200; //Where the footer starts from
#if NETCOREAPP
br.Read(cookie);
#else
for (int i = 0; i < 9; i++)
cookie[i] = br.ReadByte();
#endif
}
//SequenceEqual returns false if length is not equal, therefore we slice it to match
return vhdFooterCookie.SequenceEqual(cookie.Slice(0, 8))
|| vhdFooterCookie.SequenceEqual(cookie.Slice(1)); //If created on legacy platform
}
有一些条件编译位,但我相信您可以删除不必要的位以满足您的需要。