Windowsの場合、レジストリのHKEY_CLASSES_ROOTに、拡張子毎にアプリケーションの関連付けなどの情報が格納されている。 目的の拡張子をキーとしたノードにContent Typeの値が登録されている場合は、その値を使用できる。
private static string GetMimeTypeByExtension(string extension) { const string @default = "application/octet-stream"; var key = Registry.ClassesRoot.OpenSubKey(extension); if (key == null) return @default; var mimeType = key.GetValue("Content Type"); if (mimeType == null) return @default; else return (string)mimeType; } public static void Main(string[] args) { var extensions = new[] { ".txt", ".eml", ".html", ".jpg", ".bmp", ".wav", ".mp4", ".exe", ".dll", ".bin", ".zip", ".tar.gz", }; foreach (var extension in extensions) { Console.WriteLine("{0} => {1}", extension, GetMimeTypeByExtension(extension)); } }{1}", extension, GetMimeTypeByExtension(extension)); } }]]>
.txt => text/plain .eml => message/rfc822 .html => text/html .jpg => image/jpeg .bmp => image/bmp .wav => audio/wav .mp4 => video/mp4 .exe => application/x-msdownload .dll => application/x-msdownload .bin => application/octet-stream .zip => application/x-zip-compressed .tar.gz => application/octet-stream
FindMimeFromData関数を用いることで、データストリームからMIMEタイプを推定することが出来る。
(この項の内容は検証が不十分です。 適用に際してはリンク先のドキュメントを参照してください。)
private enum FMFD : uint { FMFD_DEFAULT = 0, FMFD_URLASFILENAME = 1 << 0, FMFD_ENABLEMIMESNIFFING = 1 << 1, FMFD_IGNOREMIMETEXTPLAIN = 1 << 2, FMFD_SERVERMIME = 1 << 3, // ? } [DllImport("urlmon")] private static extern uint FindMimeFromData(IntPtr pBC, IntPtr pwzUrl, byte[] buffer, int cbSize, [In, MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed, FMFD dwMimeFlags, [MarshalAs(UnmanagedType.LPWStr)] out string ppwzMimeOut, uint dwReserved); private static string GetMimeTypeByMagic(byte[] magic, string mimeProposed) { const uint E_INVALIDARG = 0x80070057; string mime; var ret = FindMimeFromData(IntPtr.Zero, IntPtr.Zero, magic, magic.Length, mimeProposed, FMFD.FMFD_DEFAULT, out mime, 0); if (ret == 0) return mime; else if (ret == E_INVALIDARG) throw new ArgumentException(); else return null; } public static void Main() { var image = new Bitmap(8, 8); // イメージ foreach (var format in new[] { System.Drawing.Imaging.ImageFormat.Bmp, System.Drawing.Imaging.ImageFormat.Jpeg, System.Drawing.Imaging.ImageFormat.Png, }) { using (var stream = new MemoryStream()) { image.Save(stream, format); Console.WriteLine("{0} => {1}", format, GetMimeTypeByMagic(stream.ToArray(), null)); } } // プレーンテキスト var text = "Hello, world.\r\n"; Console.WriteLine("plain text => {0}", GetMimeTypeByMagic(Encoding.Default.GetBytes(text), "text/plain")); // XML (Atomフィード) text = @"<?xml version=""1.0""> <feed xmlns=""http://www.w3.org/2005/Atom""> </feed> </xml>"; Console.WriteLine("XML => {0}", GetMimeTypeByMagic(Encoding.Default.GetBytes(text), "text/plain")); // HTML text = @"<html><body>HTML</body></html>"; Console.WriteLine("HTML => {0}", GetMimeTypeByMagic(Encoding.Default.GetBytes(text), "text/plain")); // 256バイトのランダムなストリーム var random = new Random(); for (var act = 0; act < 3; act++) { var stream = new byte[0x100]; random.NextBytes(stream); Console.WriteLine("random => {0}", GetMimeTypeByMagic(stream, "application/octet-stream")); } }{1}", format, GetMimeTypeByMagic(stream.ToArray(), null)); } } // プレーンテキスト var text = "Hello, world.\r\n"; Console.WriteLine("plain text => {0}", GetMimeTypeByMagic(Encoding.Default.GetBytes(text), "text/plain")); // XML (Atomフィード) text = @""; Console.WriteLine("XML => {0}", GetMimeTypeByMagic(Encoding.Default.GetBytes(text), "text/plain")); // HTML text = @"HTML"; Console.WriteLine("HTML => {0}", GetMimeTypeByMagic(Encoding.Default.GetBytes(text), "text/plain")); // 256バイトのランダムなストリーム var random = new Random(); for (var act = 0; act < 3; act++) { var stream = new byte[0x100]; random.NextBytes(stream); Console.WriteLine("random => {0}", GetMimeTypeByMagic(stream, "application/octet-stream")); } }]]>
Bmp => image/bmp Jpeg => image/pjpeg Png => image/x-png plain text => text/plain XML => text/xml HTML => text/html random => application/octet-stream random => application/octet-stream random => application/octet-stream
FindMimeFromDataは、渡されたデータストリームをスキャンしてMIME Type Detection in Internet ExplorerのKnown MIME Typesにあるタイプかどうかテストする。 このページには判定方法についての詳細が書かれている。
FindMimeFromDataは、通常最初の256バイトの内容を重視するとしているので、例えば256バイトを越えるファイルの内容をすべて渡すのは無駄と思われる。