Получить тип файла, не используя расширение файла c # - PullRequest
0 голосов
/ 31 августа 2018

Я знаю, что об этом уже спрашивали, но ни одно из решений не помогло мне. Я хочу знать, имеет ли файл, загруженный на мой сервер (через .ashx), тип .xlsx, .xls или .csv.

Я попытался использовать магические числа, перечисленные здесь здесь , но если я, например, изменю расширение .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 голосов
/ 31 августа 2018

Файл сам по себе является просто данными. Расширение файла позволяет вашей системе интерпретировать эти данные соответствующим образом. Без расширения файла невозможно точно определить тип файла, который вы просматриваете. (Если вы не работаете с ограниченным подмножеством типов файлов)

Однако по данным вы можете определить, какое расширение файла МОЖЕТ быть. Проект, на который ссылается Тьерри V, устарел и не поддерживается.

Вместо этого вы можете захотеть взглянуть на инструмент, подобный TrID , который использует постоянно растущую библиотеку типов файлов. Этот инструмент проанализирует файл и даст рейтинг наиболее вероятных типов файлов. Как я уже говорил, он может лишь с определенной долей уверенности сказать, какой это тип файла.

0 голосов
/ 01 сентября 2018

Я попытался использовать магические числа, перечисленные здесь, но если я, например, изменю расширение .msi на .xls, файл будет распознан как .xls ... Следующий код иллюстрирует то, что я сказал:

Да, это правда, единственное, что вы можете определить при проверке подписи файла - это формат, на котором основан файл. Таким образом, для файла «.xls» вы обнаружите, что файл имеет составной двоичный формат. Однако, как вы заметили, этот формат используется в файлах ".msi", а также в ".doc", ".ppt" и т. Д.

Кроме того, то же самое относится и к вашему обнаружению ".xlsx", оно просто проверяет, что файл имеет формат zip и такая же подпись будет найдена в ".zip", ".docx", ".ods и т. д.

Итак, вы можете проверить подпись файла и пройти через файлы, которые имеют эти два формата, но как насчет ".csv"? Здесь вы можете иметь различные байтовые значения, потому что это просто текст, он не имеет подписи.

В любом случае, я думаю, что реальный вопрос в том, какова ваша цель с этими файлами Excel? Вам нужно их обрабатывать дальше или как?
Если вам нужно обрабатывать их дальше, вам следует полагаться на неисправный механизм, который читает этот файл. Поэтому любая библиотека, выбранная для чтения файла, скорее всего, выдаст исключение из-за «нераспознанного формата» или «нераспознанной структуры» файла.

Под «нераспознанной структурой» я подразумеваю, например, в файле «.xls» ожидаемые потоки с именами «Рабочая книга», «Сводная информация» и т. Д.

0 голосов
/ 31 августа 2018

Как насчет открыть файл Excel на EPPlus из Interop и поймать исключение, если это не файл Excel

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

Или существует третье лицо (не проверено), которое проверяет тип файла.

FileInfo file = new FileInfo("C:\Hello.pdf");
if ( file.isExcel())
    Console.WriteLine("File is PDF");
...