2009-09-01 3 views
25

Я заинтересован в обнаружении типа MIME для файла в каталоге документов моего приложения iPhone. Поиск в документах не дал никаких ответов.Как вы можете читать файлы MIME-типа в объекте-c

+1

Существует еще один отличный ответ: [stackoverflow_Q] [1] [1]: HTTP: // StackOverflow .com/questions/2439020/wheres-the-iphone-mime-type-database –

ответ

53

Это немного Hacky, но он должен работать, не знаю точно, потому что я просто предполагаю, у него

Есть два варианта:

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

Шляпы для идеи, но две отрицательные точки для опечаток, которые делают код, производят ошибки –

+0

исправлены опечатки;) – slf

+1

К сожалению, в приложениях iOS это приведет к сбою больших файлов, таких как видео, которые не вписываются в память , – geon

1

В Mac OS X это будет обрабатываться через LaunchServices и UTI. На iPhone они недоступны. Поскольку единственный способ доступа данных к вашей песочнице - для вас, вы можете ее разместить, большинство приложений обладают внутренними знаниями о данных любого файла, который они могут читать.

Если у вас есть необходимость в такой функции, вы должны указать file запрос функции с Apple.

+0

это загрузка от пользователя в приложение. Я использую cocoaHTTPServer, чтобы разрешить загрузку файла через веб-браузер в устройство. Я хочу проверить, что файл имеет правильный тип, прежде чем работать с ним на устройстве. – coneybeare

+0

Конечно, я так понял. Я говорю, что это очень нетипичная потребность по сравнению с ОС, где файлы приходят и уходят независимо от приложений, поэтому это не удивительно, что для этого мало поддержки. –

0

Я не уверен, что такое практика на iPhone, но если вам разрешено, я бы использовал философию UNIX здесь: используйте программу file, которая является стандартным способом определения типа файла в операционной системе UNIX система. Он включает в себя обширную базу данных магических маркеров для обнаружения файлов. Поскольку file, вероятно, не отправлен на iPhone, вы можете включить его в свой комплект приложений. Может быть библиотека, реализующая функции file.

Кроме того, вы можете доверять браузеру. Браузеры отправляют тип MIME, о котором они догадывались где-то в заголовках HTTP. Я знаю, что я могу легко получить информацию типа MIME в PHP. Это, конечно, зависит от того, хотите ли вы доверять клиенту.

+0

Вы не можете создавать процессы на iPhone, fork() не разрешается в изолированных приложениях, поэтому использование файла не является жизнеспособным. Кроме того, я предполагаю, что вы имеете в виду доверие к серверу, а не браузеру. HTTP-сервер отправляет mimetype файла. Это может быть жизнеспособным, если он получает файлы с http-сервера, что не ясно. –

+0

Фактически он упомянул, что он запускает http-сервер в приложении в комментарии. В зависимости от того, как отправляется файл, mimetype может передаваться или не передаваться. –

5

Я использовал ответ предоставленный SLF в приложении какао (не iPhone) и заметил, что запрос 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 файл, он будет выплевывать: применение/PDF

+0

Это ** медленно **, особенно при проверке больших наборов файлов ... – danw

35

Добавить MobileCoreServices рамки.

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

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

Это красиво! Этот код просто интерпретирует тип mime из расширения файла или действительно ли он просматривает некоторую информацию заголовка в файле? Например, если я переименовал PDF-файл в конец .txt, он вернется в виде текстового файла? –

+0

№. Он распознает тип mime только с помощью указанного расширения. – Prcela

+0

Я хотел бы добавить, что есть некоторые файлы, такие как файлы docx и doc, которые не распознаются как документ –

10

Принятая ответ является проблематичным для больших файлов, так как уже упоминалось. Мое приложение имеет дело с видеофайлами, и загрузка всего видеофайла в память - хороший способ сделать 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]; 
} 
+1

yep, ваш ответ лучше выбранного выше –

+0

Autorelease ?? Это решение работает в ARC? – Vineeth

+0

@Vineeth: Очевидно, это не сработает. Но чтобы сделать его совместимым с ARC, мы можем просто удалить вызов 'autorelease' и добавить к нему функцию' @autoreleasepool {} '. – Yogi

4

на основе the Lawrence Dol/slf answer above, я решал NSURL загрузки всего файла в выпуске памяти измельчением первые несколько байтов в head-stub и получение MIMEType этого. Я не сравнивал это, но, скорее всего, это происходит быстрее.

+ (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 не работал в Swift 2. Следующая упрощенная функция возвращает тип пантомимы для данного расширения файла в 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 
}