8

Windows DLLを介してアクセスできるFindMimeFromDataメソッドは、そのUrlmon.dllようなデータが格納されているバイト配列の最初の256バイトを考慮して、メモリに格納されている特定のデータのMIMEタイプを判別できます。

しかし、そのドキュメントを読んだ後、私はWindows Internet ExplorerのMIMEタイプ検出に導かれ、このメソッドが認識できるMIMEタイプを見つけることができました。リストを参照してください。ご覧のとおり、このメソッドは26のMIMEタイプに制限されています。

だから私は誰かが私にもっと多くのMIMEタイプを持つ別のメソッドを指すことができるか、あるいは別のメソッド/クラスが私が適切だと思うMIMEタイプを含めることができるだろうかと思っていました。

4

4 に答える 4

21

更新:@GetoXはこのコードを取得し、.netコア用のNuGetパッケージにラップしました!以下を参照してください、乾杯!

それで、誰かが私にもっと多くのMIMEタイプを持つ別のメソッドを指すことができるか、あるいは別のメソッド/クラスが私が適切だと思うMIMEタイプを含めることができるかどうか疑問に思いました。

WinistaとURLMonのハイブリッドを使用して、アップロードされたファイルの実際の形式を検出します。

WinistaMIME検出

誰かがexeの名前をjpg拡張子に変更したとしても、BinaryAnalysisを使用して「実際の」ファイル形式を判別できます。swfやflvは検出されませんが、他のほとんどすべてのよく知られた形式を検出します。さらに、16進エディタを取得して、検出できるファイルを追加できます。

ファイルマジック

Winistaは、ファイルタイプとコンテンツタイプの識別に使用される署名に関する情報を含むXMLファイル「mime-type.xml」を使用して実際のMIMEタイプを検出します。例:

<!--
 !   Audio primary type
 ! -->

<mime-type name="audio/basic"
           description="uLaw/AU Audio File">
    <ext>au</ext><ext>snd</ext>
    <magic offset="0" type="byte" value="2e736e64000000"/>
</mime-type>

<mime-type name="audio/midi"
           description="Musical Instrument Digital Interface MIDI-sequention Sound">
    <ext>mid</ext><ext>midi</ext><ext>kar</ext>
    <magic offset="0" value="MThd"/>
</mime-type>

<mime-type name="audio/mpeg"
           description="MPEG Audio Stream, Layer III">
    <ext>mp3</ext><ext>mp2</ext><ext>mpga</ext>
    <magic offset="0" value="ID3"/>
</mime-type>

Winistaが実際のファイル形式の検出に失敗した場合、私はURLMonメソッドに戻りました。

public class urlmonMimeDetect
{
    [DllImport(@"urlmon.dll", CharSet = CharSet.Auto)]
    private extern static System.UInt32 FindMimeFromData(
        System.UInt32 pBC,
        [MarshalAs(UnmanagedType.LPStr)] System.String pwzUrl,
        [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer,
        System.UInt32 cbSize,
        [MarshalAs(UnmanagedType.LPStr)] System.String pwzMimeProposed,
        System.UInt32 dwMimeFlags,
        out System.UInt32 ppwzMimeOut,
        System.UInt32 dwReserverd
    );

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

    byte[] buffer = new byte[256];
    using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
        if (fs.Length >= 256)
            fs.Read(buffer, 0, 256);
        else
            fs.Read(buffer, 0, (int)fs.Length);
    }
    try
    {
        System.UInt32 mimetype;
        FindMimeFromData(0, null, buffer, 256, null, 0, out mimetype, 0);
        System.IntPtr mimeTypePtr = new IntPtr(mimetype);
        string mime = Marshal.PtrToStringUni(mimeTypePtr);
        Marshal.FreeCoTaskMem(mimeTypePtr);
        return mime;
    }
    catch (Exception e)
    {
        return "unknown/unknown";
    }
}
}

Winistaメソッドの中から、ここでURLMonにフォールバックします。

   public MimeType GetMimeTypeFromFile(string filePath)
    {
        sbyte[] fileData = null;
        using (FileStream srcFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            byte[] data = new byte[srcFile.Length];
            srcFile.Read(data, 0, (Int32)srcFile.Length);
            fileData = Winista.Mime.SupportUtil.ToSByteArray(data);
        }

        MimeType oMimeType = GetMimeType(fileData);
        if (oMimeType != null) return oMimeType;

        //We haven't found the file using Magic (eg a text/plain file)
        //so instead use URLMon to try and get the files format
        Winista.MimeDetect.URLMONMimeDetect.urlmonMimeDetect urlmonMimeDetect = new Winista.MimeDetect.URLMONMimeDetect.urlmonMimeDetect();
        string urlmonMimeType = urlmonMimeDetect.GetMimeFromFile(filePath);
        if (!string.IsNullOrEmpty(urlmonMimeType))
        {
            foreach (MimeType mimeType in types)
            {
                if (mimeType.Name == urlmonMimeType)
                {
                    return mimeType;
                }
            }
        }

        return oMimeType;
    }

netomatixからWinistaユーティリティへのWaybackMachineリンク。AFAIKは、「オープンソースのNutchクローラーシステムでmimeリーダーユーティリティクラス」をいくつか見つけ、2000年代初頭にC#の書き換えを行いました。

Winistaを使用してMimeDetectプロジェクトをホストしましたが、URLMonはここにフォールバックします(16進エディターを使用して新しいファイルタイプを提供してください): https ://github.com/MeaningOfLights/MimeDetect

この投稿で言及されている、PaulZahraによってリンクされているRegistryメソッドまたは.Net4.5メソッドを使用することもできますが Winistaが最高のIMHOです。

システム上のファイルがマルウェアに感染していないと主張していることを知っ て楽しんでください!


アップデート:

デスクトップアプリケーションの場合、WindowsAPICodePackの方がうまく機能する場合があります。

using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;

private static string GetFilePropertyItemTypeTextValueFromShellFile(string filePathWithExtension)
{
   var shellFile = ShellFile.FromFilePath(filePathWithExtension);
   var prop = shellFile.Properties.GetProperty(PItemTypeTextCanonical);
   return prop.FormatForDisplay(PropertyDescriptionFormatOptions.None);
}
于 2013-03-24T05:40:09.433 に答える
3

弾力性のある解決策を探して数時間後。@JeremyThompsonソリューションを使用して、フレームワーク.net core / .net 4.5に適合させ、nugetパッケージに入れました。

   //init
   var mimeTypes = new MimeTypes();

   //usage by filepath
   var mimeType1 = mimeTypes.GetMimeTypeFromFile(filePath);

   //usage by bytearray
   var mimeType2 = mimeTypes.GetMimeTypeFromFile(bytes);
于 2019-12-16T22:45:55.990 に答える
2

このSO投稿には複数の可能な解決策があり、少なくとも思考の糧となるでしょう。

MIMEタイプが何らかの方法でハードコードされていると宣言されているか、マシン独自の利用可能なMIMEタイプ/レジストリに依存しているかにかかわらず、それを行う唯一の実際の方法は、バイナリで読み取り、比較を行うことです。

于 2013-03-15T10:08:36.190 に答える
2

FileSignaturesが見つかりました。これは実際には優れた代替手段であり、Linuxを対象としたアプリケーションでも正常に動作します。

コンテクスト

Urlmon.dllLinuxには適していません。したがって、マルチプラットフォームアプリケーションでは機能しません。この記事はMicrosoftDocsで見つけました。これは、ファイルタイプの非常に優れたリファレンスであるファイル署名データベースへの参照を作成します(これを書いている時点では518)。

もう少し掘り下げてみると、このかなり良いプロジェクトが見つかりました:FileSignaturesnugethere。また、非常に拡張性があるため、たとえば、filesignatures.netから必要なすべての型を取得して、独自の型モデルを作成できます。

使用法

定義されたタイプを確認できます

var format = inspector.DetermineFileFormat(stream);

if(format is Pdf) {
  // Just matches Pdf
}

if(format is OfficeOpenXml) {
  // Matches Word, Excel, Powerpoint
}

if(format is Image) {
  // Matches any image format
}

または、一致したファイルタイプに基づいて、提供されるメタデータの一部を使用します

var fileFormat = _fileFormatInspector.DetermineFileFormat(stream);
var mime = fileFormat?.MediaType;

拡張性

を継承するタイプをいくつでも定義し、必要に応じてそれらをロードするようにFileFormat構成できます。FileFormatLocator

var assembly = typeof(CustomFileFormat).GetTypeInfo().Assembly;

// Just the formats defined in the assembly containing CustomFileFormat
var customFormats = FileFormatLocator.GetFormats(assembly);

// Formats defined in the assembly and all the defaults
var allFormats = FileFormatLocator.GetFormats(assembly, true);

プロジェクトのGithubで詳細を確認してください

于 2021-03-05T21:00:37.003 に答える