您如何在Objective-c中读取文件的MIME类型

问题描述 投票:33回答:9

我有兴趣在iPhone应用程序的documents目录中检测文件的MIME类型。在文档中搜索没有提供任何答案。

iphone objective-c mime mime-types
9个回答
56
投票

这有点笨拙,但应该可以,不确定,因为我只是在猜测

有两个选项:

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

43
投票

添加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);

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
}

11
投票

如其他人所提到的,接受的答案对于大文件是有问题的。我的应用程序处理视频文件,将整个视频文件加载到内存中是使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];
}

6
投票

Prcela solutionSwift 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
}

5
投票

[我在可可应用程序(不是iPhone)中使用了slf提供的答案,并且注意到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文件上调用它,它将吐出:application / pdf


4
投票

基于the Lawrence Dol/slf answer above,我已经解决了NSURL将整个文件加载到内存的问题,方法是将前几个字节切成头存根,并获取其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;
}

1
投票

在Mac OS X上,这可以通过LaunchServices和UTI处理。在iPhone上,这些功能不可用。由于将数据放入沙箱的唯一方法是将其放置在沙箱中,因此大多数应用程序都具有关于它们可以读取的任何文件的数据的内在知识。

如果需要此功能,请向Apple提出file功能请求。


0
投票

我不确定在iPhone上的做法是什么,但是如果允许的话,我会在这里使用UNIX哲学:使用程序file,这是在UNIX操作系统上检测文件类型的标准方法。系统。它包括一个庞大的魔术标记数据库,用于文件类型检测。由于file可能未在iPhone上附带,因此您可以将其包含在应用程序包中。可能有一个实现file功能的库。

或者,您可以信任浏览器。浏览器在HTTP标头中的某个位置发送他们猜测的MIME类型。我知道我可以轻松地获取PHP中的MIME类型信息。当然,这取决于您是否愿意信任客户。


0
投票

确保您导入了核心服务

import <CoreServices/CoreServices.h>

在您的文件中。

© www.soinside.com 2019 - 2024. All rights reserved.