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.
-
1There is another excellent answer: [stackoverflow_Q][1] [1]: http://stackoverflow.com/questions/2439020/wheres-the-iphone-mime-type-database – Cullen SUN Feb 21 '12 at 17:41
9 Answers
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];

- 63,018
- 25
- 139
- 189

- 22,595
- 11
- 77
- 101
-
Hats down for the idea, but 2 negative points for the typos which make the code produce errors – Marin Todorov Nov 20 '10 at 20:13
-
2Unfortunately, in iOS apps, this will crash on large files, such as videos that don't fit in memory. – geon Feb 06 '12 at 10:28
-
1
-
1@geon you may skip data loading in NSURLConnection's delegate and analyze response in `connection:didReceiveResponse:` – Apr 03 '12 at 10:08
-
I 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. – brainjam Jul 02 '13 at 15:50
-
Is 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 Feb 19 '14 at 02:55
-
@boyfarrell in truth I think it's a little of both http://en.wikipedia.org/wiki/Uniform_Type_Identifier – slf Feb 19 '14 at 16:19
-
On 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. – Fitter Man Mar 30 '15 at 20:15
-
1Sorry, but I think the type of `cachePolicy` in `[NSURLRequest -initWithURL:cachePolicy:timeoutInterval:]` is `NSURLRequestCachePolicy` but not `NSURLCacheStoragePolicy`. But anyway, thanks for your posting. – WeZZard May 06 '15 at 03:05
-
@WeZZard I saw that, and noted that it translates to `NSURLRequestReturnCacheDataElseLoad`. Not sure if that's the intended behavior... – Ky - Dec 26 '18 at 22:01
-
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
}

- 30,724
- 51
- 192
- 308

- 4,257
- 33
- 46
-
1This 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? – Daniel Farrell Feb 19 '14 at 02:56
-
-
I would like to add, there are some files, like docx and doc files that are not recognized as document – Bryan P Feb 22 '16 at 08:36
-
-
It depends on the file path extension, actually. Doesn't work for *plain_file.abcd* which returns null. – Itachi Mar 14 '17 at 08:23
-
it return nil for URL : file:///private/var/mobile/Containers/Data/Application/7FB4FACE-B83E-44D6-B7AD-6AA54D25F3FF/Documents/Inbox/pdf-5.pdf – kemdo Dec 17 '17 at 10:29
-
@kemdo instead of passing it that whole URL, just pass it the extension. That is, instead of `mimeType(fileExtension: myUrl)`, use `mimeType(fileExtension: myUrl.pathExtension)` – Ky - Feb 19 '19 at 21:23
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];
}

- 1
- 1

- 1,165
- 1
- 10
- 13
-
1
-
@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. – Yogi Aug 09 '16 at 08:56
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
}
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

- 1,528
- 1
- 17
- 17
Based on the Lawrence Dol/slf answer above, I have solved the NSURL loading the entire file into memory issue by chopping the first few bytes into a head-stub and getting the MIMEType of that. I have not benchmarked it, but it's probably faster this way too.
+ (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;
}
On Mac OS X this would be handled through LaunchServices and UTIs. On the iPhone these are not available. Since the only way for data to get into your sandbox is for you to put it there, most apps have intrinsic knowledge about the data of any file they can read.
If you have a need for such a feature you should file a feature request with Apple.

- 43,356
- 8
- 80
- 90
-
this 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. – coneybeare Sep 02 '09 at 14:30
-
Sure, 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. – Louis Gerbarg Sep 02 '09 at 16:29
I'm not sure what are the practices on iPhone, but if you're allowed to, I'd make use of UNIX philosophy here: use program file
, which is the standard way to detect filetype on an UNIX operating system. It includes a vast database of magic markers for filetype detection. Since file
is probably not shipped on iPhone, you could include it in your app bundle. There might be a library implementing file
's functionality.
Alternatively, you could trust the browser. Browsers send the MIME type they guessed somewhere in the HTTP headers. I know that I can easily grab the MIME type information in PHP. That of course depends if you're willing to trust the client.

- 9,529
- 9
- 60
- 111
-
You 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. – Louis Gerbarg Sep 10 '09 at 13:45
-
Actually 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. – Louis Gerbarg Sep 10 '09 at 13:47
Make sure are you import the coreservices
import <CoreServices/CoreServices.h>
in your file.

- 754
- 1
- 12
- 36