我正在尝试通过查看前四个字节来检测给定文件是否是ZIP文件。这是在一个iOS应用程序中所以文件句柄的东西是由Cocoa框架处理的,但实际的字节比较的东西是直接的C,我真的不知道。
unsigned char aBuffer[4];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *data = [fileHandle readDataOfLength:4];
[data getBytes:aBuffer];
if (aBuffer[0] == 0x50 && aBuffer[1] == 0x4b && aBuffer[2] == 0x03 && aBuffer[3] == 0x04) {
archiveType = ARCHIVE_TYPE_ZIP;
}
它起作用但是笨拙地打击我。有没有更好的方法来比较这4个字节? (是的,我知道它需要更多错误检查。)
答案 0 :(得分:5)
你可以使用memcmp
。它就像strcmp
,但是对于记忆。
if (memcmp([data bytes],"PK\3\4",4) == 0) {
// success
}
那就是说,既然您正在使用Objective-C,那么您应该寻找比C更高级别的实现。我建议使用您期望的数据构建NSData,然后使用[data isEqual: expectedData]
。
NSData *expectedHeader = [NSData dataWithBytes: "PK\3\4" length: 4];
if ([expectedHeader isEqual: data]) {
// success
}
如果isEqualToData:
,您也可以使用isEqual:
。我更喜欢短标识符,但isEqualToData:
更有效,并且在遇到不匹配的类型时会抛出。
您现在非常接近意图,而不是实际的机制。
@jsd澄清说他正在寻找程序员效率,而不是运行时效率。但对于将来阅读本文的人来说:忘记运行时效率。你多久检查一次拉链头?相反,担心代码有多简单,以及它可能出错的方式有多少。并且在适合时总是支持更高级别的抽象。
答案 1 :(得分:2)
您可以随时将aBuffer
放入union
,这样您只需进行一次比较即可查看:
union {
unsigned char asBytes[4];
uint32_t asInt;
} aBuffer;
...
[data getBytes:aBuffer.asBytes];
if (aBuffer.asInt == 0x504b0304) { ... } // or 0x04034b50, depending on endianness
答案 2 :(得分:1)
我认为没有更有效的方式。
编译器可能会很好地为您优化这一点。
由于它只是一个不在循环或任何东西的单一陈述,我不确定是否有理由尝试手动优化它。
你可以做的一件事就是在
中进行无符号长比较unsigned char fileCheck [4] = {0x50, 0x4b, 0x03, 0x04};
unsigned char aBuffer[4];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *data = [fileHandle readDataOfLength:4];
[data getBytes:aBuffer];
if (*(unsigned long *)aBuffer == *(unsigned long *)fileCheck) {
// it is a file
archiveType = ARCHIVE_TYPE_ZIP;
}
答案 3 :(得分:0)
这是笨拙但不太可能低效。
另一种方法是使用C的memcmp
函数。例如:
if(!memcmp(aBuffer, "PK\003\004", 4))
{
archiveType = ARCHIVE_TYPE_ZIP;
}
您可能还希望削减额外的缓冲区:
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *data = [fileHandle readDataOfLength:4];
if ([data length] >= 4 && !memcmp([data bytes], "PK\003\004", 4))
{
archiveType = ARCHIVE_TYPE_ZIP;
}
C(因此,Objective-C)保证if语句从左到右评估并尽可能提前退出,因此首先检查长度将明确避免memcmp
偏离界限。
答案 4 :(得分:-1)
您是否尝试过以下操作?
if (*((unsigned int *) aBuffer) == 'PK\3\4') {
archiveType = ARCHIVE_TYPE_ZIP;
}
这适用于iPad和iPhone等iOS设备,数据类型大小一致。
那些贬低我的人必须不熟悉多字符文字。