How can you read a files MIME-type in objective-c
Solution 1
It's a bit hacky, but it should work, don't know for sure because I'm just guessing at it
There are two options:
- If you just need the MIME type, use the timeoutInterval: NSURLRequest.
- If you want the data as well, you should use the commented out NSURLRequest.
Make sure to perform the request in a thread though, since it's synchronous.
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];
Solution 2
Add MobileCoreServices framework.
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
}
Solution 3
The accepted answer is problematic for large files, as others have mentioned. My app deals with video files, and loading an entire video file into memory is a good way to make iOS run out of memory. A better way to do this can be found here:
https://stackoverflow.com/a/5998683/1864774
Code from above 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];
}
Solution 4
Prcela solution did not work in Swift 2. The following simplified function will return the mime-type for a given file extension in 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
}
Solution 5
I was using the answer provided by slf in a cocoa app (not iPhone) and noticed that the URL request seems to be reading the entire file from disk in order to determine the mime type (not great for large files).
For anyone wanting to do this on the desktop here is the snippet I used (based on Louis's suggestion):
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;
}
If you called that on a PDF file it would spit out: application/pdf
coneybeare
http://matt.coneybeare.me @coneybeare I have had a ton iOS apps under my name and my business name. I have multiple client apps, and one from an established startup. Many of my apps have been featured by Apple. I developed two iOS apps that made it into the top 100. One of the apps held the number two spot for three weeks. Another floats in/out of the paid News top 10. My apps have over 10 million downloads. I do a ton of web work too using rails for all my sites. I do much of my own design for all the sites I have created.
Updated on March 31, 2020Comments
-
coneybeare about 4 years
I am interested in detecting the MIME-type for a file in the documents directory of my iPhone application. A search through the docs did not provide any answers.
-
coneybeare almost 15 yearsthis is an upload from a user into the app. I am using cocoaHTTPServer to allow a file upload via web-browser into the device. I want to check that the file is of the right type before working with it on the device.
-
KeremV almost 15 yearsSure, I figured as much. What I am saying is that it is a very atypical need compared to an OS where files come and go independent of apps, so it is not suprising there is little support for it.
-
KeremV almost 15 yearsYou cannot spawn processes on the iPhone, fork() is not allowed in sandboxed apps, so using file is not viable. Also, I assume you mean trust the server, not the browser. A http server sends the mimetype of a file. That may be viable if he is getting the files from an http server, which is not clear.
-
KeremV almost 15 yearsActually he mentioned he is running an http server in the app in a comment. Depending on how the file is being sent the mimetype may or may not be transmitted.
-
Marin Todorov over 13 yearsHats down for the idea, but 2 negative points for the typos which make the code produce errors
-
geon over 12 yearsUnfortunately, in iOS apps, this will crash on large files, such as videos that don't fit in memory.
-
slf over 12 years@geon good point, +1. I never said it was a perfect solution, only a hack
-
Admin about 12 years@geon you may skip data loading in NSURLConnection's delegate and analyze response in
connection:didReceiveResponse:
-
brainjam almost 11 yearsI would have thought that setting the fileUrlRequest HTTPMethod to @"HEAD" would eliminate the file load into NSData, but that doesn't seem to be the case.
-
Daniel Farrell over 10 yearsIs this code just interpreting the mime-type from the file extension or is it actually reviewing some of header information in the file?
-
Daniel Farrell over 10 yearsThis is nice a short! Is this code just interpreting the mime-type from the file extension or is it actually reviewing some of header information in the file? For example if I renamed a PDF to end in .txt would it return as a text file?
-
slf over 10 years@boyfarrell in truth I think it's a little of both en.wikipedia.org/wiki/Uniform_Type_Identifier
-
Krešimir Prcela over 10 yearsno. It recognises mime type only by given extension.
-
Basheer_CAD over 9 yearsyep, your answer is better than the selected above
-
Fitter Man about 9 yearsOn MacOS, this solution appears to load the data no matter what I do. There is another answer here that solves this without invoking a system utility.
-
WeZZard about 9 yearsSorry, but I think the type of
cachePolicy
in[NSURLRequest -initWithURL:cachePolicy:timeoutInterval:]
isNSURLRequestCachePolicy
but notNSURLCacheStoragePolicy
. But anyway, thanks for your posting. -
Bryan P over 8 yearsI would like to add, there are some files, like docx and doc files that are not recognized as document
-
Yogi almost 8 years@Vineeth: Obviously it won't work. But to make it ARC compatible we can just remove
autorelease
call and add@autoreleasepool{}
block to the function. -
Tommy over 7 yearsThis is really simple but exactly does the function! Thank you @Prcela!
-
Itachi over 7 yearsIt depends on the file path extension, actually. Doesn't work for plain_file.abcd which returns null.
-
kemdo over 6 yearsit return nil for URL : file:///private/var/mobile/Containers/Data/Application/7FB4FACE-B83E-44D6-B7AD-6AA54D25F3FF/Documents/Inbox/pdf-5.pdf
-
Ky - over 5 years@WeZZard I saw that, and noted that it translates to
NSURLRequestReturnCacheDataElseLoad
. Not sure if that's the intended behavior... -
Ky - over 5 years@kemdo instead of passing it that whole URL, just pass it the extension. That is, instead of
mimeType(fileExtension: myUrl)
, usemimeType(fileExtension: myUrl.pathExtension)
-
Itachi over 2 yearsDid someone test the time performace?