Ios 有没有更有效的方法来比较C中的字节数组
我试图通过查看前四个字节来检测给定文件是否为ZIP文件。这是在一个iOS应用程序中,所以文件句柄是由Cocoa框架处理的,但是实际的字节比较是C,我真的不知道Ios 有没有更有效的方法来比较C中的字节数组,ios,c,Ios,C,我试图通过查看前四个字节来检测给定文件是否为ZIP文件。这是在一个iOS应用程序中,所以文件句柄是由Cocoa框架处理的,但是实际的字节比较是C,我真的不知道 unsigned char aBuffer[4]; NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; NSData *data = [fileHandle readDataOfLength:4]; [
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个字节?(是的,我知道它需要更多的错误检查。)您可以使用。它就像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
}
如果isEqual:
,也可以使用isequaldata:
。我更喜欢短标识符,但是isEqualToData:
更有效,并且在暴露于不匹配的类型时抛出
你现在非常接近你的意图,而不是实际的机制
@jsd澄清说,他在寻找程序员的效率,而不是运行时的效率。但对于将来阅读本文的人来说:忘记运行时效率吧。您多久检查一次zip标头?相反,要担心代码有多简单,有多少方法会出错。并且在合适的时候总是倾向于更高层次的抽象。你可以选择使用。它就像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
}
如果isEqual:
,也可以使用isequaldata:
。我更喜欢短标识符,但是isEqualToData:
更有效,并且在暴露于不匹配的类型时抛出
你现在非常接近你的意图,而不是实际的机制
@jsd澄清说,他在寻找程序员的效率,而不是运行时的效率。但对于将来阅读本文的人来说:忘记运行时效率吧。您多久检查一次zip标头?相反,要担心代码有多简单,有多少方法会出错。并且在合适的时候总是倾向于更高层次的抽象。这很笨拙,但不太可能是低效的 另一种方法是使用C的函数。例如:
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
越界。这很笨拙,但不太可能是低效的
另一种方法是使用C的函数。例如:
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
越界。您始终可以将aBuffer
放在联合中,因此您只需进行一次比较即可进行检查:
union {
unsigned char asBytes[4];
uint32_t asInt;
} aBuffer;
...
[data getBytes:aBuffer.asBytes];
if (aBuffer.asInt == 0x504b0304) { ... } // or 0x04034b50, depending on endianness
您可以始终将aBuffer
放在union
中,因此您只需进行一次比较即可进行检查:
union {
unsigned char asBytes[4];
uint32_t asInt;
} aBuffer;
...
[data getBytes:aBuffer.asBytes];
if (aBuffer.asInt == 0x504b0304) { ... } // or 0x04034b50, depending on endianness
我想不出比这更有效的方法了
编译器可能会很好地为您优化这一点
由于它只是一条不在循环中的语句,所以我不确定是否有理由手动优化它
您可以做的一件事是进行无符号长比较,如中所示
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;
}
我想不出比这更有效的方法了
编译器可能会很好地为您优化这一点
由于它只是一条不在循环中的语句,所以我不确定是否有理由手动优化它
您可以做的一件事是进行无符号长比较,如中所示
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;
}
你试过以下方法吗
if (*((unsigned int *) aBuffer) == 'PK\3\4') {
archiveType = ARCHIVE_TYPE_ZIP;
}
这应该适用于iPad和iPhone等iOS设备,因为它们的数据类型大小是一致的
那些否决我的人一定不熟悉多字符文字。您尝试过以下方法吗
if (*((unsigned int *) aBuffer) == 'PK\3\4') {
archiveType = ARCHIVE_TYPE_ZIP;
}
这应该适用于iPad和iPhone等iOS设备,因为它们的数据类型大小是一致的
那些向下投票的me必须不熟悉多字符文字。添加一些可以比较的内容:无符号字符引用缓冲区[4]={0x50,0x4b,0x03,0x04}
对于遵循普通的Cocoa约定,我非常喜欢NSData-isEqual:
解决方案。为此,您可以使用合适的NSData
键和NSNumber
值为文件类型创建前四个字节的字典。这是否有助于简化整个代码?查找类型应该是一行,而不是一堆if语句。当我说“高效”时,我指的是程序员高效,而不是运行时高效。代码越短越好。我喜欢你使用两个NSData的想法,我不知道你可以用这样的C文本来构造它们。这就是我最后做的。唯一的区别是我使用了isEqualToData:而不是isEqual:。谢谢你这么好的回答。我真的以为你就是这个意思,我的意思是说,这显然是为了子孙后代,但我显然做得太差了。我将添加等质量数据:
;我一直在使用isEqual:
,因为它比较短,而且我没有做足够的比较来考虑性能。此外,我不打算将此添加到答案中,但是如果您担心额外的分配,您可以始终为BytesaRequalto:(void*)ptr length:(nsInteger)添加一个类别长度
并在其中使用memcmp。类别非常适合移动概念上简单的c