web-dev-qa-db-ja.com

どのようにしてobjective-cでファイルのMIMEタイプを読み取ることができますか

IPhoneアプリケーションのドキュメントディレクトリにあるファイルのMIMEタイプを検出することに興味があります。ドキュメントを検索しても回答はありませんでした。

31
coneybeare

少しハッキーですが、うまくいくはずです。推測しているだけなので、よくわかりません。

2つのオプションがあります。

  1. MIMEタイプだけが必要な場合は、timeoutInterval:NSURLRequestを使用します。
  2. データも必要な場合は、コメントアウトされた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];
54
slf

MobileCoreServices フレームワークを追加します。

目標C:

#import <MobileCoreServices/MobileCoreServices.h>    
NSString *fileExtension = [myFileURL pathExtension];
NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL);
NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);

迅速:

import MobileCoreServices

func mimeType(fileExtension: String) -> String? {

    guard !fileExtension.isEmpty else { return nil }

    if let utiRef = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension as CFString, nil) {
        let uti = utiRef.takeUnretainedValue()
        utiRef.release()

        if let mimeTypeRef = UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType) {
            let mimeType = MIMETypeRef.takeUnretainedValue()
            mimeTypeRef.release()
            return mimeType as String
        }
    }

    return nil
}
42
Prcela

他の人が述べたように、受け入れられた答えは大きなファイルには問題があります。私のアプリはビデオファイルを扱っており、ビデオファイル全体をメモリにロードすることは、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];
}
10
Adam Lockhart

PrcelaソリューションSwift 2では機能しませんでした。次の簡略化された関数は、指定されたファイル拡張子のMIMEタイプをSwift 2で返します。

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
}
6
dreamlab

ココアアプリ(iPhoneではなく)でslfによって提供された回答を使用していたところ、URLリクエストがMIMEタイプを判別するためにディスクからファイル全体を読み取っているように見えました(大きなファイルには適していません)。

デスクトップでこれを実行したい人のために、ここに私が使用したスニペットがあります(ルイスの提案に基づく):

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

5
danw

上記の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;
}
4
got nate

Mac OS Xでは、これはLaunchServicesとUTIを通じて処理されます。 iPhoneでは、これらは使用できません。データがサンドボックスに入る唯一の方法はそこに置くことなので、ほとんどのアプリは、読み取ることができるすべてのファイルのデータについて本質的な知識を持っています。

このような機能が必要な場合は、Appleに file 機能のリクエストを送信してください。

1
Louis Gerbarg

IPhoneでの慣例はわかりませんが、許可されている場合は、ここでUNIXの哲学を利用します。UNIXでファイルタイプを検出する標準的な方法であるプログラムfileを使用します。オペレーティング・システム。ファイルタイプ検出用のマジックマーカーの膨大なデータベースが含まれています。 fileはおそらくiPhoneに同梱されていないため、アプリバンドルに含めることができます。 fileの機能を実装するライブラリがあるかもしれません。

または、ブラウザを信頼することもできます。ブラウザは、推測したMIMEタイプをHTTPヘッダーのどこかに送信します。 PHPでMIMEタイプ情報を簡単に取得できることはわかっています。もちろん、それはあなたがクライアントを信頼しても構わないと思っているかどうかに依存します。

0
Ivan Vučica