我有兴趣在我的 iPhone 应用程序的文档目录中检测文件的 MIME 类型。通过文档搜索没有提供任何答案。
9 回答
这有点hacky,但它应该可以工作,不确定,因为我只是在猜测它
有两种选择:
- 如果只需要 MIME 类型,请使用 timeoutInterval: NSURLRequest。
- 如果你也想要数据,你应该使用注释掉的 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];
添加MobileCoreServices框架。
目标 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);
迅速:
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
}
正如其他人所提到的,接受的答案对于大文件是有问题的。我的应用程序处理视频文件,将整个视频文件加载到内存中是让 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];
}
Prcela解决方案在Swift 2中不起作用。以下简化函数将返回 Swift 2 中给定文件扩展名的 mime 类型:
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
}
我在可可应用程序(不是 iPhone)中使用 slf 提供的答案,并注意到 URL 请求似乎是从磁盘读取整个文件以确定 mime 类型(对于大文件来说不是很好)。
对于任何想在桌面上执行此操作的人,这里是我使用的片段(基于 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;
}
如果你在 PDF 文件上调用它,它会吐出:application/pdf
基于上面的 Lawrence Dol/slf 答案,我通过将前几个字节切入头存根并获取其 MIMEType 解决了 NSURL 将整个文件加载到内存中的问题。我没有对它进行基准测试,但这种方式也可能更快。
+ (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;
}
在 Mac OS X 上,这将通过 LaunchServices 和 UTI 处理。在 iPhone 上,这些不可用。由于数据进入沙盒的唯一方法是让您将其放在那里,因此大多数应用程序对它们可以读取的任何文件的数据都有内在的了解。
如果您需要这样的功能,您应该向 Apple提出功能请求。
我不确定 iPhone 上的做法是什么,但如果允许,我会在这里使用 UNIX 哲学: use program file
,这是在 UNIX 操作系统上检测文件类型的标准方法。它包括一个庞大的用于文件类型检测的魔法标记数据库。由于file
可能未在 iPhone 上提供,因此您可以将其包含在您的应用程序包中。可能有一个实现file
's 功能的库。
或者,您可以信任浏览器。浏览器在 HTTP 标头中的某处发送他们猜到的 MIME 类型。我知道我可以很容易地在 PHP 中获取 MIME 类型信息。这当然取决于您是否愿意信任客户。
确保您导入核心服务
import <CoreServices/CoreServices.h>
在你的文件中。