DOBON.NET DOBON.NETプログラミング掲示板過去ログ

MIMEタイプの判別

  • 題名: MIMEタイプの判別
  • 著者: ralris
  • 日時: 2009/11/20 22:29:30
  • ID: 25883
  • この記事の返信元:
    • (なし)
  • この記事への返信:
  • ツリーを表示
環境/言語:[C#.NET 3.5]
分類:[.NET]

ファイルをアップロードするプログラムを作っているのですが、
MIMEタイプの判別をどうやってするか考えています。
どうやって判別すればいいのでしょうか。
■No25883に返信(ralrisさんの記事)
> ファイルをアップロードするプログラムを作っているのですが、
> MIMEタイプの判別をどうやってするか考えています。
> どうやって判別すればいいのでしょうか。

  クライアント側がMIMEタイプの指定してアップ
  するんですか?

  サーバーサイドで判断させるんですか?

  アップロードするって、何をアップさせるか決まって
  いないんですか?

  で・・・クラサバソフトではなくASP.NET?

  よく解りませんネ〜

以上。
クライアントサイドで判別したいです。
アップロードさせるファイルは決まってないです。
ちなみ、ASP.NETではなく普通の.NETです。

■No25884に返信(オショウさんの記事)
> ■No25883に返信(ralrisさんの記事)
>>ファイルをアップロードするプログラムを作っているのですが、
>>MIMEタイプの判別をどうやってするか考えています。
>>どうやって判別すればいいのでしょうか。
>
>   クライアント側がMIMEタイプの指定してアップ
>   するんですか?
>
>   サーバーサイドで判断させるんですか?
>
>   アップロードするって、何をアップさせるか決まって
>   いないんですか?
>
>   で・・・クラサバソフトではなくASP.NET?
>
>   よく解りませんネ〜
>
> 以上。
ファイルの中身で判断するには、urlmon.dllのFindMimeFromDataを使う方法があります。

pinvoke.net: FindMimeFromData (urlmon)
http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData

拡張子から調べる方法であればもっといろいろ考えられますので、検索していただければ簡単に見つかると思います。
FindMimeFromDataのサンプルコードに
// call it this way:
Trace.Write("MimeType is " + MimeTypeFrom(Encoding.ASCII.GetBytes("%PDF-"), "text/plain"));
とありますが、
第1引数にファイルの内容を入れるのは分かります。ただ、第2引数に何を入れればいいのかわかりません。
http://dobon.net/vb/dotnet/file/filestream.html
の方法で読み込み、MimeTypeFromの第一引数にbsを指定しましたがこのようなエラーが出ます。
静的でないフィールド、メソッド、またはプロパティ 'Project.Program.MimeTypeFrom(byte[], string)' で、オブジェクト参照が必要です
どうすればいいのでしょうか。


■No25886に返信(管理人さんの記事)
> ファイルの中身で判断するには、urlmon.dllのFindMimeFromDataを使う方法があります。
>
> pinvoke.net: FindMimeFromData (urlmon)
> http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData
>
> 拡張子から調べる方法であればもっといろいろ考えられますので、検索していただければ簡単に見つかると思います。
■No25888に返信(ralrisさんの記事)

  VBのコードですが・・・

<DllImport("urlmon.dll", CharSet:=CharSet.Auto)> _
Private Function FindMimeFromData( _
ByVal pBC As IntPtr, _
<MarshalAs(UnmanagedType.LPWStr)> ByVal pwzUrl As String, _
<MarshalAs(UnmanagedType.LPArray, ArraySubType:=UnmanagedType.I1, SizeParamIndex:=3)> ByVal pBuffer As Byte(), _
ByVal cbSize As Integer, _
<MarshalAs(UnmanagedType.LPWStr)> ByVal pwzMimeProposed As String, _
ByVal dwMimeFlags As Integer, _
ByRef ppwzMimeOut As IntPtr, _
ByVal dwReserved As Integer) As Integer
End Function

Public Function getMimeFromFile(ByVal file As String) As String

Dim mimeout As IntPtr

If Not System.IO.File.Exists(file) Then
Throw New FileNotFoundException()
End If

Dim MaxContent As Integer = CInt(New FileInfo(file).Length)

If MaxContent > 256 Then MaxContent = 256

Using fs As New FileStream(file, FileMode.Open)
Dim buf(MaxContent) As Byte
fs.Read(buf, 0, MaxContent)
fs.Close()
Dim result As Integer = FindMimeFromData(IntPtr.Zero, file, buf, MaxContent, Nothing, 0, mimeout, 0)
End Using

Dim mime As String = Marshal.PtrToStringUni(mimeout)

Marshal.FreeCoTaskMem(mimeout)

Return mime

End Function

  問題なく動作したと思ってますが・・・

以上。参考まで
VBは分からないのでなんとかVB->C#コンバーターで読めるようにしましたが、

FindMimeFromDataの戻り値がないとエラーが出るのですがなんて返せばよいのでしょうか。
エラー 1 'Project.Program.FindMimeFromData(System.IntPtr, string, byte[], int, string, int, ref System.IntPtr, int)': 値を返さないコード パスがあります。

あと Console.WriteLine(getMimeFromFile("C:\\picture.jpg")); とやると
エラー 2 静的でないフィールド、メソッド、またはプロパティ 'Project.Program.getMimeFromFile(string)' で、オブジェクト参照が必要です
というエラーが出ます。

以下、VB->C#コンバーター(http://codeconverter.sharpdevelop.net/SnippetConverter.aspx)を使って変換したソース

[DllImport("urlmon.dll", CharSet = CharSet.Auto)]
private 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, ref IntPtr ppwzMimeOut, int dwReserved)
{
}


public string getMimeFromFile(string file)
{
IntPtr mimeout = default(IntPtr);

if (!System.IO.File.Exists(file)) {
throw new FileNotFoundException();
}

int MaxContent = Convert.ToInt32(new FileInfo(file).Length);

if (MaxContent > 256)
MaxContent = 256;

using (FileStream fs = new FileStream(file, FileMode.Open)) {
byte[] buf = new byte[MaxContent + 1];
fs.Read(buf, 0, MaxContent);
fs.Close();
int result = FindMimeFromData(IntPtr.Zero, file, buf, MaxContent, null, 0, ref mimeout, 0);
}

string mime = Marshal.PtrToStringUni(mimeout);

Marshal.FreeCoTaskMem(mimeout);

return mime;

}
■No25890に返信(ralrisさんの記事)
> VBは分からないのでなんとかVB->C#コンバーターで読めるようにしましたが、

pinvoke.net: FindMimeFromData (urlmon)
http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData

にC#のコードがありますが、なぜそれを使わずに、わざわざVBのコードを変換して使用されるのでしょうか?
getMimeFromFileを残し、FindMimeFromDataの部分をC#のコードに変えるとエラーはなくなりましたが、
この行に2つのエラーが生じています。
int result = FindMimeFromData(IntPtr.Zero, file, buf, MaxContent, null, 0, ref mimeout, 0);

'Project.Program.FindMimeFromData(System.IntPtr, string, byte[], int, string, int, out System.IntPtr, int)' に最も適しているオーバーロード メソッドには無効な引数がいくつか含まれています。

引数 '7' は 'out' キーワードと共に渡されなければなりません。

あと、
Console.WriteLine("MIME: " + getMimeFromFile("C:\\picture.jpg"));
とした際静的でないフィールド、メソッド、またはプロパティでオブジェクト参照が必要です
と出て、
public string getMimeFromFile(string file) を
static string getMimeFromFile(string file) とするとエラーは消えるのですがこれでいいのでしょうか。

■No25891に返信(管理人さんの記事)
> ■No25890に返信(ralrisさんの記事)
>>VBは分からないのでなんとかVB->C#コンバーターで読めるようにしましたが、
>
> pinvoke.net: FindMimeFromData (urlmon)
> http://www.pinvoke.net/default.aspx/urlmon.FindMimeFromData
>
> にC#のコードがありますが、なぜそれを使わずに、わざわざVBのコードを変換して使用されるのでしょうか?
2009/11/22(Sun) 18:30:48 編集(投稿者)

■No25892に返信(ralrisさんの記事)

  VBのコードでいじわるしたつもりはないのですが・・・

        [DllImport("urlmon.dll", CharSet = CharSet.Auto )]
        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);

        private string GetMimeTypeFromFile(string file){

            IntPtr mimeout;
            FileInfo    fi;

            fi = new FileInfo(file);

            if( fi.Exists == false )
                throw new FileNotFoundException(file);

            int MaxContent = (int)fi.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 mimeout, 0);

            if (result != 0)
                throw Marshal.GetExceptionForHR(result);

            string mime = Marshal.PtrToStringUni(mimeout);

            Marshal.FreeCoTaskMem(mimeout);

            return mime;

        }

動作確認してありますが・・・

以上。参考まで
追伸・・・

読み込むバイト数は、256バイトでもOKなようです。
検索してみたら、256バイトのもあれば、4096バイトのも
いろいろありましたが、最低256バイトあればよいようです。

※ 画像以外のファイルの場合は、注意が必要かも。

以上。参考まで
提示されたコードに差し替えてみたら見事MIMEタイプが認識されました。
ただ、空のファイルやフォルダを指定すると止まってしまいます。
例外処理をしたいのですがMSDNにはそのようなことが書いてありませんでした。
どう例外処理をすればいいのですか?

■No25894に返信(オショウさんの記事)
> 追伸・・・
>
> 読み込むバイト数は、256バイトでもOKなようです。
> 検索してみたら、256バイトのもあれば、4096バイトのも
> いろいろありましたが、最低256バイトあればよいようです。
>
> ※ 画像以外のファイルの場合は、注意が必要かも。
>
> 以上。参考まで
■No25895に返信(ralrisさんの記事)
> ただ、空のファイルやフォルダを指定すると止まってしまいます。
> 例外処理をしたいのですがMSDNにはそのようなことが書いてありませんでした。
> どう例外処理をすればいいのですか?

  いや・・・だから・・・
  ファイルのありなしをチェックするとか、ファイルサイズを
  見てやるとか・・・

  判定するコードを書く部位は・・・
  ファイルの有無は既に書かれてますので、後はサイズのみな
  ので、

int MaxContent = (int)fi.Length;
if (MaxContent > 4096) MaxContent = 4096;

  このMaxContentが、256バイト未満なら、エラーとして止める。

※ ちゃんとコード書いてあるんだから、全てオンブにダッコでは
  なく、コードの解読して勉強して下さい!

以上。
  • 題名: Re[13]: MIMEタイプの判別
  • 著者: ralris
  • 日時: 2009/11/23 11:38:31
  • ID: 25897
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
そうですね。失礼しました。
オショウさん、管理人さんのお陰で解決しました。
ありがとうございます。

■No25896に返信(オショウさんの記事)
> ■No25895に返信(ralrisさんの記事)
>>ただ、空のファイルやフォルダを指定すると止まってしまいます。
>>例外処理をしたいのですがMSDNにはそのようなことが書いてありませんでした。
>>どう例外処理をすればいいのですか?
>
>   いや・・・だから・・・
>   ファイルのありなしをチェックするとか、ファイルサイズを
>   見てやるとか・・・
>
>   判定するコードを書く部位は・・・
>   ファイルの有無は既に書かれてますので、後はサイズのみな
>   ので、
>
> int MaxContent = (int)fi.Length;
> if (MaxContent > 4096) MaxContent = 4096;
>
>   このMaxContentが、256バイト未満なら、エラーとして止める。
>
> ※ ちゃんとコード書いてあるんだから、全てオンブにダッコでは
>   なく、コードの解読して勉強して下さい!
>
> 以上。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板