从NSData中确定MIME类型?

36

如何确定NSData对象的MIME类型?我打算让用户从他们的iPhone上传视频/图片,并将该文件包装在NSData类中。

我想知道是否可以从NSData中获取MIME类型。这个问题只有很少的答案,最近的一个是2010年(4年前!)。谢谢!

NSData *data; // can be an image or video
NSString *mimeType = [data getMimetype]; // how would I implement getMimeType

你可以再添加一个字段来声明MIME类型,并将其一并发送。 - aust
无法从数据本身确定数据的MIME类型,最多只能做出有根据的猜测。 - Hot Licks
如果您想添加额外的MIME类型,可以在此处找到它们的十六进制值:https://en.wikipedia.org/wiki/List_of_file_signatures - Joseph Beuys' Mum
4个回答

54
根据类似帖子中ml的回答,我已经为NSData添加了mime类型的确定:
ObjC:
+ (NSString *)mimeTypeForData:(NSData *)data {
    uint8_t c;
    [data getBytes:&c length:1];

    switch (c) {
        case 0xFF:
            return @"image/jpeg";
            break;
        case 0x89:
            return @"image/png";
            break;
        case 0x47:
            return @"image/gif";
            break;
        case 0x49:
        case 0x4D:
            return @"image/tiff";
            break;
        case 0x25:
            return @"application/pdf";
            break;
        case 0xD0:
            return @"application/vnd";
            break;
        case 0x46:
            return @"text/plain";
            break;
        default:
            return @"application/octet-stream";
    }
    return nil;
}

Swift:

static func mimeType(for data: Data) -> String {

    var b: UInt8 = 0
    data.copyBytes(to: &b, count: 1)

    switch b {
    case 0xFF:
        return "image/jpeg"
    case 0x89:
        return "image/png"
    case 0x47:
        return "image/gif"
    case 0x4D, 0x49:
        return "image/tiff"
    case 0x25:
        return "application/pdf"
    case 0xD0:
        return "application/vnd"
    case 0x46:
        return "text/plain"
    default:
        return "application/octet-stream"
    }
}

这段代码只处理主要文件类型,但你可以根据需要进行完善:所有文件的签名都在这里提供,只需使用与我相同的模式即可。

附注:所有对应的MIME类型在这里提供。


嘿@blee908,这可能是一个有效的答案,你觉得呢? :) - Tib
我们如何检测音频文件? - Ankush
@Ankush,请查看上述链接中提到的签名列表:https://en.wikipedia.org/wiki/List_of_file_signatures - Tib
2
然后找到你想要检测的音频文件类型以及每种文件类型的情况。例如:根据文件签名数组,WMA的第一个字节是0x30,因此添加case 0x30: return @"audio/x-ms-wma"; break; - Tib
对于扩展名为.doc的文件,我得到的是application/vnd而不是application/word,我不确定为什么会这样。 - jayant rawat
显示剩余5条评论

38

❤️ Swift

extension Data {
    private static let mimeTypeSignatures: [UInt8 : String] = [
        0xFF : "image/jpeg",
        0x89 : "image/png",
        0x47 : "image/gif",
        0x49 : "image/tiff",
        0x4D : "image/tiff",
        0x25 : "application/pdf",
        0xD0 : "application/vnd",
        0x46 : "text/plain",
        ]

    var mimeType: String {
        var c: UInt8 = 0
        copyBytes(to: &c, count: 1)
        return Data.mimeTypeSignatures[c] ?? "application/octet-stream"
    }
}

完美运行 - Francisco Castro
我们可以为文档或演示文稿文件设置类型吗? - Jigar Tarsariya
1
这可能会返回很多错误结果。 - rmaddy
文档呢?doc还是docx? - Rishabh Shukla

4

你说你正在上传这个数据,那么你应该已经知道它的MIME类型了。你创建了数据对象,你知道数据来自哪里,并且存在有限数量的MIME类型。所以使用适用于您的数据的任何一个。对于图像,可能是image/jpegimage/png。对于视频,有许多video/类型。您可以在Mac上的/etc/apache2/mime.types中找到长列表的MIME类型字符串。根据您拥有的视频类型选择一个或多个。

确定MIME类型是一个棘手的问题;NSData可以编码任何类型的二进制数据。唯一确定编码的方法是检查字节。这反过来意味着必须对不同文件类型中存在的字节流有一些了解。在许多(但不是所有)情况下,可以使用查找字典,而针对常见文件类型可能会有开源实现。为了了解涉及的内容,请在Mac上尝试man file并查看/usr/share/file/magic/中各种文件类型的识别方式(file命令不生成MIME类型,但它分析文件内容以尝试识别文件类型,因此原理相同)。


感谢您的解释。实际情况比较复杂。我正在编写一个API调用,但不知道用户传递了什么内容。我只知道它是NSData类,并且可能是图像或视频。为了通过AFNetworking正确上传文件,我需要MIME类型。 - blee908
你的服务器需要知道确切的 MIME 类型吗?你可以始终退而求其次,使用 application/octet-stream 表示“某种二进制数据”。如果你需要更具体的类型,最好的方法可能是将其加载到 AVFoundation 类(例如 AVAsset)中,然后查看元数据以选择 MIME 类型。 - Tom Harrington
非常接近。事实证明,"application/octet-stream"似乎可以使用(我测试了PNG和JPEG,但输入相同的MIME类型),但AFNetworking需要知道文件扩展名,因此您需要使用"mypic.jpeg"或"mypic.png"传入一个NSString *filename,而不是"mypic"。 - blee908
好的,我不使用AFNetworking,所以对此不了解。不过它是开源的,所以更改它总是一个选择。 - Tom Harrington

3
据我所知,NSData只是一个包装字节数组的数据对象:

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/Reference/Reference.html

...所以我想到的一种方法是检查字节本身,然后从中推断出类型,如果您想发现它的MIME类型。这里有一个例子:从NSData或UIImage中查找图像类型的方法

我还发现了这个:确定从文件加载的NSData的MIME类型;它引用了一些内部数据库(我猜),可用于MIME类型查找。

但正如Tom Harrington在他的回答中所说,这可能会变得棘手,这取决于您正在处理什么。

编辑...

当然,第二种解决方案依赖于文件扩展名,显然您没有,但我相信您已经注意到了这一点。


感谢您的反馈! - blee908

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接