有什么方法可以仅根据我指定的base64字符串来确定上传的文件是zip文件还是docx/xlsx文件,因为我没有文件扩展名。
到目前为止,我找到了使用像这样的文件扩展名来执行此操作的解决方案
private static readonly byte[] ZIP_DOCX = { 80, 75, 3, 4 };
public static string GetMimeType(byte[] file, string fileName)
{
string extension = Path.GetExtension(fileName) == null
? string.Empty
: Path.GetExtension(fileName).ToUpper();
if (file.Take(4).SequenceEqual(ZIP_DOCX))
{
mime = extension == ".DOCX" ? "application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "application/x-zip-compressed";
}
}
但正如我所说,这个解决方案对我不起作用,因为我没有文件扩展名。有什么想法吗?
听起来很有趣,所以我就玩了一下。这不是基于规范,所以不是超级可靠。我只是提取了一个 Excel 文件和一个 Word 文件,并猜测了可能的识别特征是什么。似乎有效。
public enum FileKind
{
NotZip,
OtherZip,
Xlsx,
Docx
}
public static class FileKindDecoder
{
public static FileKind DetermineFileKind(string base64)
{
XElement? contentTypesXml;
var bytes = Convert.FromBase64String(base64);
using (var stream = new MemoryStream(bytes))
using (var zip = OpenZip(stream))
{
if (zip == null)
return FileKind.NotZip;
var contentTypesEntry = zip.GetEntry(@"[Content_Types].xml");
if (contentTypesEntry == null)
return FileKind.OtherZip;
contentTypesXml = ReadXmlFromZip(contentTypesEntry);
}
if (contentTypesXml == null)
return FileKind.OtherZip;
XNamespace ns = @"http://schemas.openxmlformats.org/package/2006/content-types";
if (contentTypesXml.Name != ns + "Types")
return FileKind.OtherZip;
foreach (var overrideElement in contentTypesXml.Elements(ns + "Override"))
{
var contentType = overrideElement.Attribute("ContentType")?.Value;
if (contentType == null)
continue;
if (contentType.Contains("spreadsheetml"))
return FileKind.Xlsx;
if (contentType.Contains("wordprocessingml"))
return FileKind.Docx;
}
return FileKind.OtherZip;
static ZipArchive? OpenZip(Stream stream)
{
try
{
return new ZipArchive(stream);
}
catch (InvalidDataException)
{
return null;
}
}
static XElement? ReadXmlFromZip(ZipArchiveEntry entry)
{
using var stream = entry.Open();
try
{
return XElement.Load(stream);
}
catch (XmlException)
{
return null;
}
}
}
}