2013-09-16 2 views
0

Я пытаюсь прочитать в первых четырех байтах файла. Я знаю, что это работает правильно со следующим кодом C:Objective-C/эквивалент какао fread

FILE *file = fopen(URL.path.UTF8String, "rb"); 
uint data; 
fread(&data, 4, 1, file); 
NSLog(@"%u", data); 

Это печатает: 205

Я пытаюсь найти эквивалентный способ сделать это в Objective-C/с функциями какао. Я пробовал несколько вещей. Я чувствую, как следующее близко:

NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:URL error:nil]; 
NSData *data2 = [fileHandle readDataOfLength:4]; 
NSLog(@"%@", data2); 
NSLog(@"%u", (uint)data2.bytes); 

Это печатает: < cd000000>

и: 1703552

Как и ожидалось, первые четыре байта файла действительно CD000000.

Я предполагаю, что есть одна из двух вещей, вызывающих разницу (или оба):

  1. Fread не считая 0s после CD. Я подтвердил это, только прочитав в 1 байт с файлом, но иногда это число будет больше одного байта, поэтому я не могу его ограничивать. Нужно ли мне вручную проверять, что байты, входящие, не являются 00?

  2. Это как-то связано с контентом. Я пробовал ряд функций, таких как CFSwapInt32BigToHost, но не смог вернуть правильное значение. Было бы здорово, если бы кто-нибудь мог просветить меня о том, как это работает/влияет на это.

ответ

5

Вы не разыскиваете данные.

NSLog(@"%u", (uint)data2.bytes); // wrong 

«Быстрым хак» версия такова:

NSLog(@"%u", *(uint *) data2.bytes); // hack 

Более надежное решение требует копирования на переменную где-нибудь, чтобы получить правильное выравнивание, но это не имеет значения на всех платформах :

uint value; 
[data getBytes:&value length:sizeof(value)]; 
NSLog(@"%u", value); 

Другим решением является явно читать данные байт в байт, который является самым портативным, не имеет никаких проблем с выравниванием на любой платформе, и не имеет никаких проблем порядка байтов на любой платформе:

unsigned char *p = data.bytes; 
uint value = (unsigned) p[0] | ((unsigned) p[1] << 8) | 
      ((unsigned) p[2] << 16) | ((unsigned) p[3] << 24); 
NSLog(@"%u", value); 

Как вы можете видеть, есть веские причины, почему мы избежать ввода двоичных данных в файлах себя, и оставить его в библиотеки или использовать текстовые форматы.

Это не может быть проблемой при использовании порядка байтов, потому что fread() работает правильно. Функция fread() и метод -readDataOfLength: оба дадут вам тот же результат: кусок байтов.

+1

(Эквивалент), альтернативный memcpy: '[data getBytes: & value length: sizeof (value)]'. –

+0

Ваш «портативный» пример кода должен учитывать размер типа 'uint'. В противном случае это объясняет тонкие проблемы. – CouchDeveloper

+0

@CouchDeveloper: «Портативное» решение предназначено для портативного чтения 4-байтового целого, ** не ** для портативного чтения 'uint'. Он переносится, потому что 'uint' гарантированно будет не менее 4 байтов. –

-1

fread() в двоичном режиме ничего не будет делать, чтобы ваши данные, вы получите байт, поскольку они находятся в файле.

Это абсолютно байтовый заказ, который вызывает это, но я ничего не знаю о API Objective C API от Apple. Я не понимаю, почему вам не нужно делать обращения с указателями к объекту data2, даже (почему не data2.bytes сбой, и data2->bytes нужен?).

Кроме того, в документации для NSData ничего не говорится о порядке байтов, который я мог бы найти.

+0

'data2.bytes' - это синтаксис Objective-C для доступа к атрибутам. –

+0

'data2.bytes' предназначен для доступа к объекту объекта; 'data2-> bytes' будет обращаться к переменной экземпляра (член мыслительной структуры), если и только если у вас есть доступ к этой переменной экземпляра (ivars защищены по умолчанию, поэтому вы можете получить доступ только к этому ivar, если вы были в реализации NSData) , Синтаксис доступа к ресурсам эквивалентен выражению сообщения (вызов метода): 'data2.bytes' ==' [data2 bytes] '. –

1

Вы пытаетесь переинтерпретировать последовательность из 4 байтов в качестве беззнакового int. Это не гарантирует работу на всех платформах. Он будет работать только в том случае, если sizeof (unsigned int) равен 4. И он будет работать, только если порядок байтов будет одинаковым для чтения и записи.

Кроме того, вы не печатаете скаляры правильно с помощью NSLog.

+0

Он интерпретирует указатель как неподписанный int. –

+0

@NikolaiRuhe Да, это тоже во второй части образца при использовании свойства 'bytes'. ;) (Я имел в виду первую часть образца, где uint заполнен 4 байтами) – CouchDeveloper

+0

А, я вижу, правильно. –