2009-09-01 16 views
25

Estoy interesado en detectar el tipo MIME para un archivo en el directorio de documentos de mi aplicación de iPhone. Una búsqueda a través de los documentos no proporcionó ninguna respuesta.¿Cómo se puede leer un archivo de tipo MIME en Object-C

+1

Hay otra respuesta excelente: [stackoverflow_Q] [1] [1]: http: // stackoverflow .com/questions/2439020/wheres-the-iphone-mime-type-database –

Respuesta

53

Es un poco hacky, pero debería funcionar, no se sabe con seguridad porque sólo estoy adivinando que

Hay dos opciones:

  1. Si sólo necesita el tipo MIME , use el timeoutInterval: NSURLRequest.
  2. Si también desea los datos, debe usar la NSURLRequest comentada.

Sin embargo, asegúrese de realizar la solicitud en un hilo, ya que es sincrónico.

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]; 
+0

Disculpa por la idea, pero 2 puntos negativos por los errores tipográficos que hacen que el código produzca errores –

+0

corrigieron el error tipográfico;) – slf

+1

Desafortunadamente, en las aplicaciones de iOS, esto se bloqueará en archivos grandes, como los que no caben en la memoria . – geon

1

En Mac OS X esto se manejaría a través de LaunchServices y UTI. En el iPhone, estos no están disponibles. Dado que la única forma de que los datos ingresen a su sandbox es que usted los coloque allí, la mayoría de las aplicaciones tienen un conocimiento intrínseco sobre los datos de cualquier archivo que puedan leer.

Si necesita una de estas características, debe solicitar una función a file con Apple.

+0

es una carga de un usuario a la aplicación. Estoy utilizando cocoaHTTPServer para permitir la carga de un archivo a través del navegador web en el dispositivo. Quiero verificar que el archivo sea del tipo correcto antes de trabajar con él en el dispositivo. – coneybeare

+0

Claro, pensé que sí. Lo que estoy diciendo es que es una necesidad muy atípica en comparación con un sistema operativo donde los archivos entran y salen independientemente de las aplicaciones, por lo que no sorprende que haya poco apoyo para ello. –

0

No estoy seguro de cuáles son las prácticas en iPhone, pero si está permitido hacerlo, utilizaría la filosofía de UNIX aquí: use el programa file, que es la forma estándar para detectar el tipo de archivo en un UNIX sistema. Incluye una amplia base de datos de marcadores mágicos para la detección de tipo de archivo. Como es probable que file no se envíe en el iPhone, puede incluirlo en el paquete de su aplicación. Puede haber una biblioteca implementando la funcionalidad file.

Como alternativa, podría confiar en el navegador. Los navegadores envían el tipo MIME que supusieron en algún lugar de los encabezados HTTP. Sé que puedo tomar fácilmente la información del tipo MIME en PHP. Eso, por supuesto, depende de si está dispuesto a confiar en el cliente.

+0

No puede generar procesos en el iPhone, fork() no está permitido en aplicaciones de espacio aislado, por lo que no es viable utilizar el archivo. Además, supongo que te refieres a confiar en el servidor, no en el navegador. Un servidor http envía el tipo MIME de un archivo. Eso puede ser viable si está obteniendo los archivos de un servidor http, lo que no está claro. –

+0

En realidad, mencionó que está ejecutando un servidor http en la aplicación en un comentario. Dependiendo de cómo se envíe el archivo, el tipo mimet puede transmitirse o no. –

5

que estaba usando la respuesta proporcionada por el SLF en una aplicación de cacao (no iPhone) y se dio cuenta de que la solicitud de URL parece estar leyendo todo el archivo desde el disco con el fin de determinar el tipo MIME (no muy bien para los grandes archivos).

Para cualquiera que desee hacer esto en el escritorio aquí es el fragmento utilicé (basado en la sugerencia de 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; 
} 

Si llamó a que en un archivo PDF que sería escupir: application/pdf

+0

Esto es ** lento **, especialmente cuando se comprueban grandes conjuntos de archivos ... – danw

35

Agregar MobileCoreServices framework.

C Objetivo:

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

Swift:

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 

}

+1

¡Este es un buen short! ¿Está este código simplemente interpretando el tipo mime de la extensión de archivo o está realmente revisando parte de la información del encabezado en el archivo? Por ejemplo, si cambio el nombre de un PDF para que termine en .txt, ¿se devolverá como un archivo de texto? –

+0

no. Reconoce el tipo de mimo solo por la extensión dada. – Prcela

+0

Me gustaría agregar, hay algunos archivos, como archivos docx y doc que no se reconocen como documento –

10

La respuesta aceptada es problemático para archivos de gran tamaño, como otros han mencionado. Mi aplicación trata con archivos de video, y cargar un archivo de video completo en la memoria es una buena manera de hacer que iOS se quede sin memoria.Una mejor manera de hacer esto se puede encontrar aquí:

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

Código desde arriba enlace:

+ (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]; 
} 
+1

sí, su respuesta es mejor que la seleccionada arriba –

+0

Autorelease ?? ¿Esta solución funciona en ARC? – Vineeth

+0

@Vineeth: Obviamente no funcionará. Pero para hacerlo compatible con ARC, podemos simplemente eliminar la llamada 'autorelease' y agregar el bloque' @autoreleasepool {} 'a la función. – Yogi

4

Basado en the Lawrence Dol/slf answer above, he resuelto el NSURL cargar el archivo completo en cuestión de memoria cortando los primeros pocos bytes en un talón de cabeza y obteniendo el MIMEType de eso. No lo he comparado, pero probablemente también sea más rápido de esta manera.

+ (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; 
} 
5

Prcela solution no funcionó en Swift 2. La siguiente función simplificada devolverá el tipo MIME para una extensión de archivo determinado en 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 
} 
Cuestiones relacionadas