webentwicklung-frage-antwort-db.com.de

Wie können Sie einen MIME-Typ von Dateien in Objective-c lesen?

Ich bin daran interessiert, den MIME-Typ für eine Datei im Dokumentenverzeichnis meiner iPhone-Anwendung zu ermitteln. Eine Suche in den Dokumenten lieferte keine Antworten.

28
coneybeare

Es ist ein bisschen hackig, aber es sollte funktionieren, weiß es nicht genau, weil ich es nur vermute

Es gibt zwei Möglichkeiten:

  1. Wenn Sie nur den MIME-Typ benötigen, verwenden Sie timeoutInterval: NSURLRequest.
  2. Wenn Sie auch die Daten wünschen, sollten Sie das auskommentierte NSURLRequest verwenden.

Stellen Sie jedoch sicher, dass Sie die Anforderung in einem Thread ausführen, da sie synchron ist.

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

Fügen Sie MobileCoreServices framework hinzu.

Ziel 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);

Schnell:

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
}
39
Prcela

Die akzeptierte Antwort ist für große Dateien problematisch, wie andere bereits erwähnt haben. Meine App beschäftigt sich mit Videodateien. Wenn Sie eine komplette Videodatei in den Arbeitsspeicher laden, können Sie dafür sorgen, dass iOS nicht mehr über genügend Arbeitsspeicher verfügt. Einen besseren Weg finden Sie hier:

https://stackoverflow.com/a/5998683/1864774

Code vom obigen Link:

+ (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 Lösung funktionierte nicht in Swift 2 . Die folgende vereinfachte Funktion gibt den Mime-Typ für eine bestimmte Dateierweiterung in Swift 2 zurück:

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

Ich verwendete die Antwort von slf in einer Kakao-App (nicht iPhone) und bemerkte, dass die URL-Anforderung die gesamte Datei von der Festplatte zu lesen scheint, um den Mime-Typ zu bestimmen (nicht ideal für große Dateien).

Für jeden, der dies auf dem Desktop tun möchte, ist hier der von mir verwendete Ausschnitt (basierend auf Louis 'Vorschlag):

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;
}

Wenn Sie das in einer PDF -Datei aufrufen, würde dies auslaufen: application/pdf

5
danw

Basierend auf der Antwort von Lawrence Dol/slf oben habe ich die NSURL beim Laden der gesamten Datei in den Speicherproblem gelöst, indem ich die ersten paar Bytes in einen Head-Stub zerhackt und den MIMEType davon erhalte. Ich habe es nicht getestet, aber es ist wahrscheinlich auch schneller so. 

+ (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

Unter Mac OS X wird dies über LaunchServices und UTIs abgewickelt. Auf dem iPhone sind diese nicht verfügbar. Da die einzige Möglichkeit, Daten in Ihre Sandbox zu bekommen, darin besteht, sie dort abzulegen, verfügen die meisten Apps über fundiertes Wissen über die Daten aller Dateien, die sie lesen können.

Wenn Sie eine solche Funktion benötigen, sollten Sie file eine Funktionsanforderung bei Apple anfordern.

1
Louis Gerbarg

Ich bin nicht sicher, was die Praktiken auf dem iPhone sind, aber wenn Sie dazu berechtigt sind, würde ich hier die UNIX-Philosophie verwenden: Verwenden Sie das Programm file, das die Standardmethode zum Erkennen von Dateitypen auf einem UNIX-Betriebssystem ist. Es enthält eine umfangreiche Datenbank mit magischen Markern für die Erkennung von Dateitypen. Da file wahrscheinlich nicht auf dem iPhone ausgeliefert wird, können Sie es in Ihr App-Paket aufnehmen. Möglicherweise gibt es eine Bibliothek, die die Funktionalität von file implementiert.

Alternativ können Sie dem Browser vertrauen. Browser senden den ermittelten MIME-Typ irgendwo in den HTTP-Headern. Ich weiß, dass ich die Informationen zum MIME-Typ in PHP problemlos abrufen kann. Das hängt natürlich davon ab, ob Sie dem Kunden vertrauen wollen.

0
Ivan Vučica