不使用文件扩展名C#获取文件类型

时间:2018-08-31 13:57:13

标签: c# excel mime-types mime

我知道以前已经有人问过这个问题,但是没有一个解决方案对我有用。 我想知道上传到我的服务器(通过.ashx)的文件的类型是.xlsx,.xls还是.csv。

我尝试使用列出的here上的幻数,但是例如,如果我将.msi的扩展名更改为.xls,则该文件将被识别为.xls ... 以下代码说明了我所说的话:

private bool IsValidFileType(HttpPostedFile file)
{
    using (var memoryStream = new MemoryStream())
    {
        file.InputStream.CopyTo(memoryStream);
        byte[] buffer = memoryStream.ToArray();

        //Check exe and dll
        if (buffer[0] == 0x4D && buffer[1] == 0x5A)
        {
            return false;
        }

        //Check xlsx
        if (buffer.Length >= 3 &&
            buffer[0] == 0x50 && buffer[1] == 0x4B &&
            buffer[2] == 0x03 && buffer[3] == 0x04 ||
            buffer[0] == 0x50 && buffer[1] == 0x4B &&
            buffer[2] == 0x05 && buffer[3] == 0x06)
        {
            return true;
        }

        //Check xls
        if (buffer.Length >= 7 &&
            buffer[0] == 0xD0 && buffer[1] == 0xCF &&
            buffer[2] == 0x11 && buffer[3] == 0xE0 &&
            buffer[4] == 0xA1 && buffer[5] == 0xB1 &&
            buffer[6] == 0x1A && buffer[7] == 0xE1)
        {
            return true;
        }

        return false;
    }
}

然后我尝试使用urlmon.dll,类似于以下内容,但它仍将文件识别为.xls

    [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false)]
    static extern int FindMimeFromData(
        IntPtr pBC,
        [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
        [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.I1, SizeParamIndex=3)] byte[] pBuffer,
        int cbSize,
        [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
        int dwMimeFlags,
        out IntPtr ppwzMimeOut,
        int dwReserved);

    public static string GetMimeFromFile(string file)
    {
        if (!File.Exists(file))
            throw new FileNotFoundException(file + " not found");

        int MaxContent = (int)new FileInfo(file).Length;
        if (MaxContent > 4096) MaxContent = 4096;
        FileStream fs = File.OpenRead(file);


        byte[] buf = new byte[MaxContent];
        fs.Read(buf, 0, MaxContent);
        fs.Close();
        int result = FindMimeFromData(IntPtr.Zero, file, buf, MaxContent, null, 0, out IntPtr mimeout, 0);

        if (result != 0)
            throw Marshal.GetExceptionForHR(result);
        string mime = Marshal.PtrToStringUni(mimeout);
        Marshal.FreeCoTaskMem(mimeout);
        return mime;
    }

我当时在想也许应该尝试使用某些库(例如 ExcelDataReader )打开上传的文件,但是我不确定这是否是最好的方法。

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

如何通过EPPlus的{​​{1}}打开Excel文件,如果不是Excel文件则捕获异常

Interop

或者有一个3rd party(未经测试)可以验证文件的类型。

FileInfo fileInfo = new FileInfo(filePath);
ExcelPackage package = null;
try
{
    package = new ExcelPackage(fileInfo);
}
catch(Exception exception)
{
}

答案 1 :(得分:0)

文件本身就是数据。文件扩展名使您的系统能够相应地解释该数据。没有文件扩展名,就无法绝对确定要查看的文件类型。 (除非您使用的是有限类型的文件类型)

但是,您可以从数据中推断出可能是哪个文件扩展名。 Thierry V引用的项目已过时且未维护。

您可能想看看TrID之类的工具,该工具使用不断增长的文件类型库。 该工具将分析文件并给出最可能的文件类型的排名。 就像我之前说过的,它只能以有限的确定性告诉您它可能是哪种文件类型。

答案 2 :(得分:0)

  

我尝试使用此处列出的幻数,但是例如,如果我将.msi的扩展名更改为.xls,则该文件将被识别为.xls ...下面的代码说明了我所说的话:

是的,在检查文件签名时唯一可以确定的就是文件所基于的格式。因此,对于“ .xls”文件,您将检测到该文件为复合二进制格式。但是,您已经注意到,“。msi”文件中使用了这种格式,“。doc”,“。ppt”等中也使用了这种格式。

此外,对“ .xlsx”的检测也是如此,只是检查文件是否为zip格式,并在“ .zip”,“。docx”,“。ods”中找到相同的签名。 ”等。

因此,您可以检查文件的签名并通过这两种格式的文件,但是“ .csv”呢?在这里,您可以使用各种字节值,因为它只是纯文本,没有签名。

无论如何,我认为真正的问题是使用这些Excel文件的目标是什么?您需要进一步处理它们还是什么?
如果需要进一步处理它们,则应依靠正在读取该文件的机制的失败。因此,无论您选择哪个库来读取文件,都可能由于文件的“无法识别的格式”或“无法识别的结构”而引发异常。

通过“无法识别的结构”,我的意思是,例如,在“ .xls”文件中,它应该具有名为“ Workbook”,“ SummaryInformation”等的流。