web-dev-qa-db-fra.com

Comment pouvez-vous lire un type de fichier MIME dans objective-c

Je suis intéressé par la détection du type MIME pour un fichier dans le répertoire de documents de mon application iPhone. Une recherche dans la documentation n'a fourni aucune réponse.

28
coneybeare

C'est un peu hacky, mais ça devrait marcher, je ne le sais pas vraiment parce que je le devine

Il y a deux options:

  1. Si vous avez juste besoin du type MIME, utilisez timeoutInterval: NSURLRequest.
  2. Si vous voulez également les données, vous devez utiliser le NSURLRequest commenté.

Veillez cependant à exécuter la demande dans un thread, car il est synchrone.

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

Ajouter MobileCoreServices framework.

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

Rapide:

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

La réponse acceptée est problématique pour les gros fichiers, comme d'autres l'ont mentionné. Mon application traite les fichiers vidéo et le chargement d'un fichier vidéo complet dans la mémoire est un bon moyen de faire en sorte que iOS manque de mémoire. Une meilleure façon de faire cela peut être trouvée ici:

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

Code du lien ci-dessus:

+ (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 solution n'a pas fonctionné dans Swift 2 . La fonction simplifiée suivante renverra le type mime pour une extension de fichier donnée dans 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

J'utilisais la réponse fournie par slf dans une application cacao (pas d'iPhone) et remarquais que la requête d'URL semblait lire l'intégralité du fichier à partir du disque afin de déterminer le type MIME (pas génial pour les gros fichiers).

Voici l'extrait que j'ai utilisé (basé sur la suggestion de Louis) pour ceux qui souhaitent le faire sur le bureau:

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

Si vous appeliez cela sur un fichier PDF, il cracherait: application/pdf

5
danw

Sur la base de la réponse de Lawrence Dol/slf ci-dessus , j'ai résolu le problème de NSURL en chargeant le fichier entier en mémoire en découpant les premiers octets dans une tête-stub et en obtenant le type MIMET. Je ne l'ai pas évalué, mais c'est probablement plus rapide de cette façon aussi. 

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

Sur Mac OS X, cela serait géré via LaunchServices et les UTI. Sur l'iPhone, ceux-ci ne sont pas disponibles. Étant donné que le seul moyen pour les données d'entrer dans votre sandbox est de les y placer, la plupart des applications possèdent une connaissance intrinsèque des données des fichiers qu'elles peuvent lire.

Si vous avez besoin d'une telle fonctionnalité, vous devez file une demande de fonctionnalité avec Apple.

1
Louis Gerbarg

Je ne sais pas quelles sont les pratiques sur l'iPhone, mais si vous y êtes autorisé, j'utiliserais ici la philosophie d'UNIX: utilisez le programme file, qui est le moyen standard de détecter un type de fichier sur un système d'exploitation UNIX. Il comprend une vaste base de données de marqueurs magiques pour la détection de types de fichiers. Étant donné que file n'est probablement pas livré sur iPhone, vous pouvez l'inclure dans votre bundle d'applications. Il se peut qu'une bibliothèque implémente les fonctionnalités de file.

Alternativement, vous pouvez faire confiance au navigateur. Les navigateurs envoient le type MIME qu'ils ont deviné quelque part dans les en-têtes HTTP. Je sais que je peux facilement récupérer les informations de type MIME en PHP. Cela dépend bien sûr si vous êtes prêt à faire confiance au client.

0
Ivan Vučica