С++ чтение с выравниванием по секторам

Я спрашиваю об этом, потому что у меня проблемы с пониманием чтения с выравниванием по секторам, когда мы читаем необработанное устройство.

Предположим, что мы находимся в Windows, и мы используем функцию ReadFile() C для чтения x байтов с устройства.

Я знаю, что мы можем читать только данные, выровненные по секторам, но недавно я обнаружил функцию SetFilePointer(), которая позволяет нам поместить указатель в x байтов устройства, которое мы ранее открыли с помощью CreateFile().

Мой вопрос в том, нужно ли нам читать данные, выровненные по секторам, если мы используем SetFilePointer(), например, так:

SetFilePointer(device, 12, NULL, FILE_BEGIN);

(устройство представляет собой HANDLE для существующего устройства, для этого примера давайте предположим, что это USB-накопитель), в этом примере мы устанавливаем указатель, указывающий на 12-й байт, начиная с FILE_BEGIN.

Если бы я должен был прочитать эквивалент одного сектора (512 байт), начиная с этого 12-го байта, мне нужно было бы сделать мою функцию чтения такой:

ReadFile(device, sector, (512 - 12), &bytesRead, NULL)

или вот так:

ReadFile(device, sector, 512, &bytesRead, NULL)

Несмотря ни на что, спасибо!


person drk    schedule 06.07.2017    source источник


Ответы (2)


Мой вопрос в том, нужно ли нам читать данные, выровненные по секторам, если мы используем SetFilePointer(), например, так:

SetFilePointer(device, 12, NULL, FILE_BEGIN);

... то вы больше не читаете данные, выровненные по секторам, и вы получите ошибку 87 в вызове ReadFile. Чтение данных, выровненных по секторам, означает не только то, что вы должны читать блоки размером с сектор, но вы всегда должны читать блоки, которые начинаются на границах секторов.

Вы должны искать сектор, содержащий интересующие вас байты (так, position/sector_size*sector_size), читать весь сектор и извлекать интересующие вас байты из прочитанных вами данных.

person Matteo Italia    schedule 06.07.2017
comment
поэтому я могу использовать SetFilePointer(), чтобы указать на что угодно, но я не могу использовать ReadFile(), если SetFilePointer() не указывает на начало сектора? - person drk; 06.07.2017
comment
Да; в общем, нет смысла искать невыровненные позиции, если вы работаете на необработанных устройствах. - person Matteo Italia; 06.07.2017
comment
@MatteoItalia Я пробовал это в проекте, и если я, например, поставлю SetFilePointer() в 40, например, и использую ReadFile() для 512 байт, это сработает, почему? не должно ли это дать мне ошибку, потому что я читаю вне порядка секторов? - person jeyejow; 06.07.2017
comment
Это зависит от того, что хочет делать драйвер или устройство, но это не поддерживается, как объяснено в ссылке в моем предыдущем ответе. Это может сработать, но это просто удача, смените устройство, версию Windows, драйвер или что-то еще, и это больше не будет работать. Играйте по правилам и проблем не будет. - person Matteo Italia; 06.07.2017
comment
@jeyejow: ты тот же пользователь, что и drk? - person Matteo Italia; 06.07.2017
comment
@MatteoItalia нет, я только что нашел вопрос и решил попробовать то, что спрашивал дрк - person jeyejow; 06.07.2017
comment
@MatteoItalia, так что мне всегда нужно делать floor(position/512) * 512 и ставить туда указатель? это правильный путь? - person jeyejow; 06.07.2017
comment
Да (хотя нет необходимости явно указывать пол — целочисленное деление уже работает правильно). - person Matteo Italia; 06.07.2017

Смотря как..

  • если вы хотите, чтобы то, что находится в вашем буфере, представляло весь сектор устройства и отображало его с помощью struct* или байтовых смещений - обычно так это и делается. тогда ваши смещения, отправленные в SetFilePointer, должны быть выровнены по размеру сектора, а затем считаны буферы размером с сектор. Итак, SetFilePointer(0) -> ReadFile(512 байт)

  • Если вам все равно и вам нужны только байты 12-16, SetFilePointer(12) -> Read(4bytes).

Я бы выбрал решение 1, потому что это, вероятно, упростит чтение и поддержку кода в долгосрочной перспективе.

person Michaël Roy    schedule 06.07.2017
comment
но вы можете использовать только ReadFile() и читать байты, выровненные по секторам, например 512, 1024 и т. д., за раз - person drk; 06.07.2017
comment
Затем невыровненный SetFilePointers() также должен завершиться ошибкой. - person Michaël Roy; 06.07.2017