iPhone アプリケーションのドキュメント ディレクトリにあるファイルの MIME タイプを検出することに関心があります。ドキュメントを検索しても答えはありませんでした。
9 に答える
少しハッキーですが、うまくいくはずです。推測しているだけなので、よくわかりません
次の 2 つのオプションがあります。
- MIME タイプだけが必要な場合は、timeoutInterval: NSURLRequest を使用します。
- データも必要な場合は、コメントアウトされた NSURLRequest を使用する必要があります。
ただし、同期であるため、必ずスレッドでリクエストを実行してください。
NSString* filePath = [[NSBundle mainBundle] pathForResource:@"imagename" ofType:@"jpg"];
NSString* fullPath = [filePath stringByExpandingTildeInPath];
NSURL* fileUrl = [NSURL fileURLWithPath:fullPath];
//NSURLRequest* fileUrlRequest = [[NSURLRequest alloc] initWithURL:fileUrl];
NSURLRequest* fileUrlRequest = [[NSURLRequest alloc] initWithURL:fileUrl cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:.1];
NSError* error = nil;
NSURLResponse* response = nil;
NSData* fileData = [NSURLConnection sendSynchronousRequest:fileUrlRequest returningResponse:&response error:&error];
fileData; // Ignore this if you're using the timeoutInterval
// request, since the data will be truncated.
NSString* mimeType = [response MIMEType];
[fileUrlRequest release];
他の人が述べたように、受け入れられた答えは大きなファイルには問題があります。私のアプリはビデオ ファイルを処理しますが、ビデオ ファイル全体をメモリにロードすると、iOS のメモリが不足してしまいます。これを行うためのより良い方法は、次の場所にあります。
https://stackoverflow.com/a/5998683/1864774
上記のリンクのコード:
+ (NSString*) mimeTypeForFileAtPath: (NSString *) path {
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
return nil;
}
// Borrowed from https://stackoverflow.com/questions/5996797/determine-mime-type-of-nsdata-loaded-from-a-file
// itself, derived from https://stackoverflow.com/questions/2439020/wheres-the-iphone-mime-type-database
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)[path pathExtension], NULL);
CFStringRef mimeType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
CFRelease(UTI);
if (!mimeType) {
return @"application/octet-stream";
}
return [NSMakeCollectable((NSString *)mimeType) autorelease];
}
PrcelaソリューションはSwift 2では機能しませんでした。次の簡略化された関数は、Swift 2 で指定されたファイル拡張子の MIME タイプを返します。
import MobileCoreServices
func mimeTypeFromFileExtension(fileExtension: String) -> String? {
guard let uti: CFString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension as NSString, nil)?.takeRetainedValue() else {
return nil
}
guard let mimeType: CFString = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() else {
return nil
}
return mimeType as String
}
cocoa アプリ (iPhone ではない) で slf が提供する回答を使用していたところ、MIME タイプを判別するために URL 要求がディスクからファイル全体を読み取っているように見えることに気付きました (大きなファイルには適していません)。
デスクトップでこれを行いたい人のために、私が使用したスニペットを次に示します (Louis の提案に基づく):
NSString *path = @"/path/to/some/file";
NSTask *task = [[[NSTask alloc] init] autorelease];
[task setLaunchPath: @"/usr/bin/file"];
[task setArguments: [NSArray arrayWithObjects: @"-b", @"--mime-type", path, nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
[task waitUntilExit];
if ([task terminationStatus] == YES) {
NSData *data = [file readDataToEndOfFile];
return [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
} else {
return nil;
}
PDFファイルでそれを呼び出すと、次のように吐き出されます:application/pdf
上記の Lawrence Dol/slf の回答に基づいて、最初の数バイトをヘッドスタブに切り刻み、その MIMEType を取得することで、ファイル全体をメモリにロードする NSURL の問題を解決しました。ベンチマークはしていませんが、おそらくこの方法でも高速です。
+ (NSString*) mimeTypeForFileAtPath: (NSString *) path {
// NSURL will read the entire file and may exceed available memory if the file is large enough. Therefore, we will write the first fiew bytes of the file to a head-stub for NSURL to get the MIMEType from.
NSFileHandle *readFileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
NSData *fileHead = [readFileHandle readDataOfLength:100]; // we probably only need 2 bytes. we'll get the first 100 instead.
NSString *tempPath = [NSHomeDirectory() stringByAppendingPathComponent: @"tmp/fileHead.tmp"];
[[NSFileManager defaultManager] removeItemAtPath:tempPath error:nil]; // delete any existing version of fileHead.tmp
if ([fileHead writeToFile:tempPath atomically:YES])
{
NSURL* fileUrl = [NSURL fileURLWithPath:path];
NSURLRequest* fileUrlRequest = [[NSURLRequest alloc] initWithURL:fileUrl cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:.1];
NSError* error = nil;
NSURLResponse* response = nil;
[NSURLConnection sendSynchronousRequest:fileUrlRequest returningResponse:&response error:&error];
[[NSFileManager defaultManager] removeItemAtPath:tempPath error:nil];
return [response MIMEType];
}
return nil;
}
Mac OS X では、これは LaunchServices と UTI によって処理されます。iPhone では、これらは使用できません。データをサンドボックスに入れる唯一の方法はサンドボックスに入れることであるため、ほとんどのアプリは、読み取ることができるファイルのデータに関する固有の知識を持っています。
このような機能が必要な場合は、Apple に機能リクエストを提出してください。
iPhone でどのような慣行が行われているかはわかりませんが、許可されている場合は、ここで UNIX の哲学を利用したいと思います: use programfileは、UNIX オペレーティング システムでファイル タイプを検出する標準的な方法です。ファイルタイプ検出用のマジック マーカーの膨大なデータベースが含まれています。はおそらく iPhone に同梱されていないためfile、アプリ バンドルに含めることができます。fileの機能を実装するライブラリがあるかもしれません。
または、ブラウザを信頼することもできます。ブラウザーは、推測した MIME タイプを HTTP ヘッダーのどこかに送信します。PHP で MIME タイプ情報を簡単に取得できることはわかっています。もちろん、それはクライアントを信頼できるかどうかによって異なります。
コアサービスをインポートしていることを確認してください
import <CoreServices/CoreServices.h>
あなたのファイルに。