【问题标题】:How can you read a files MIME-type in objective-c如何在 Objective-C 中读取 MIME 类型的文件
【发布时间】:2010-11-24 17:30:54
【问题描述】:

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

【问题讨论】:

标签: iphone objective-c mime mime-types


【解决方案1】:

确保您导入了核心服务

import <CoreServices/CoreServices.h>

在您的文件中。

【讨论】:

    【解决方案2】:

    添加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
    }
    

    【讨论】:

    • 这是一个不错的短片!这段代码只是从文件扩展名中解释 mime 类型,还是实际上是在查看文件中的一些头信息?例如,如果我将 PDF 重命名为以 .txt 结尾,它会以文本文件的形式返回吗?
    • 没有。它仅通过给定的扩展名识别 mime 类型。
    • 我想补充一下,有一些文件,比如 docx 和 doc 文件无法识别为文档
    • 这很简单,但功能确实如此!谢谢@Prcela!
    • 这实际上取决于文件路径扩展名。不适用于返回 null 的 plain_file.abcd
    【解决方案3】:

    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
    }
    

    【讨论】:

      【解决方案4】:

      基于the Lawrence Dol/slf answer above,我通过将前几个字节切入头存根并获取其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;
      }
      

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 是的,你的答案比上面选择的要好
        • @Vineeth:显然这行不通。但是为了使其与 ARC 兼容,我们可以删除 autorelease 调用并将 @autoreleasepool{} 块添加到函数中。
        【解决方案6】:

        我在可可应用程序(不是 iPhone)中使用 slf 提供的答案,并注意到 URL 请求似乎是从磁盘读取整个文件以确定 mime 类型(不适用于大文件)。

        对于任何想在桌面上执行此操作的人,这里是我使用的 sn-p(基于 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

        【讨论】:

          【解决方案7】:

          这有点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];
          

          【讨论】:

          • 对这个想法表示赞同,但对导致代码产生错误的拼写错误有 2 个负面影响
          • 不幸的是,在 iOS 应用程序中,这会在大文件上崩溃,例如无法放入内存的视频。
          • @geon 好点,+1。我从来没有说过这是一个完美的解决方案,只是一个 hack
          • @geon 你可以跳过 NSURLConnection 的委托中的数据加载并分析connection:didReceiveResponse:中的响应
          • 抱歉,我认为[NSURLRequest -initWithURL:cachePolicy:timeoutInterval:]cachePolicy 的类型是NSURLRequestCachePolicy,但不是NSURLCacheStoragePolicy。但无论如何,谢谢你的发帖。
          【解决方案8】:

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

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

          【讨论】:

          • 你不能在 iPhone 上生成进程,fork() 在沙盒应用中是不允许的,所以使用文件是不可行的。另外,我假设您的意思是信任服务器,而不是浏览器。 http 服务器发送文件的 mimetype。如果他从 http 服务器获取文件,这可能是可行的,但不清楚。
          • 实际上他在评论中提到他正在应用程序中运行一个http服务器。根据发送文件的方式,可能会或可能不会传输 mimetype。
          【解决方案9】:

          在 Mac OS X 上,这将通过 LaunchServices 和 UTI 处理。在 iPhone 上,这些不可用。由于数据进入沙盒的唯一方法是让您将其放在那里,因此大多数应用程序对它们可以读取的任何文件的数据都有内在的了解。

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

          【讨论】:

          • 这是用户上传到应用程序的内容。我正在使用 cocoaHTTPServer 允许通过网络浏览器将文件上传到设备中。我想在设备上使用它之前检查文件的类型是否正确。
          • 当然,我也这么认为。我要说的是,与文件独立于应用程序来来去去的操作系统相比,这是一种非常非典型的需求,因此对它的支持很少也就不足为奇了。
          猜你喜欢
          • 1970-01-01
          • 2011-08-02
          • 2011-04-20
          • 2010-11-21
          • 2010-09-30
          • 2014-06-10
          • 2014-01-30
          • 2015-09-13
          • 2023-04-01
          相关资源
          最近更新 更多