#c #file #io
#c #файл #io
Вопрос:
В Windows WriteFile()
функция имеет вызываемый параметр lpOverlapped
, который позволяет указать смещение, с которым выполняется запись в файл.
Мне было интересно, есть ли fwrite()
кросс-платформенный эквивалент этого?
Я вижу, что если файл открыт с rb
флагом, я мог бы использовать fseek()
для записи в определенное смещение. Мой вопрос — будет ли этот подход эквивалентен overlapped WriteFile()
и приведет ли он к одинаковому поведению на всех платформах?
Предыстория
Причина, по которой мне это нужно, заключается в том, что я записываю заблокированные потоки сжатых данных в файл, и я хочу иметь возможность загружать определенный блок из файла и иметь возможность его распаковывать. Итак, в принципе, если я отслеживаю, где начинается блок в файле, я могу загрузить блок и распаковать его более эффективным способом. Я знаю, что, вероятно, есть лучшие способы сделать это, но мне нужно это решение для некоторой обратной совместимости.
Комментарии:
1. Используйте
fseek
передfwrite
.2.
fwrite()
это C stdio, а не C I / O.
Ответ №1:
Предполагая, что вы согласны с использованием функций POSIX, а не только вещей из стандартных библиотек C или C , решение pwrite
(иначе: позиционированная запись).
ssize_t rc = pwrite(file_handle, data_ptr, data_size, destination_offset);
Комментарии:
1. Примечание:
pwrite
ближе кwrite(2)
, чемfwrite(3)
. Но тогда, какWriteFile
и;pwrite
,write
, иWriteFile
все это в основном тонкие оболочки над системными вызовами, гдеfwrite
более высокий уровень с буферизацией пользовательского пространства.2. Я думаю, что это то, о чем на самом деле просит OP, поскольку он уже использует специфичный для Windows
WriteFile
вызов.3. Яр. Я хотел прояснить различие, ничего плохого в ответе (я проголосовал).
Ответ №2:
Я думаю, вы путаете «перекрытие» и «перезапись» / «смещение». Я не изучал особенности того, почему Microsoft явно указывает, что перекрывающиеся записи включают параметр для смещения (я думаю, это имеет смысл, как я описываю ниже). В общем, когда Microsoft говорит о «перекрытом» вводе-выводе, они говорят о том, как синхронизировать такие события, как начало записи файла, получение уведомления о завершении записи и начало другой записи в файл, которая может перекрываться или не перекрываться с предыдущей записью. В этом последнем случае под перекрытием я подразумеваю то, что, по вашему мнению, означает перекрытие, то есть перекрытие содержимого файла. Принимая во внимание, что Microsoft означает, что запись файла перекрывается по времени с запуском вашего потока или нет. Обратите внимание, что это становится очень сложным, если несколько потоков могут записать один и тот же файл.
Если возможно, и, конечно, если вам нужен переносимый код, вы хотите избежать всей этой ерунды и просто выполнять простейшую запись, возможную в каждом контексте, что означает избегать оптимизаций Microsoft, таких как «overlapped IO», если вам действительно не нужна производительность. (И если вам нужна абсолютно оптимальная производительность, вы можете самостоятельно кэшировать файл и управлять перекрытиями, а затем записать его один раз от начала до конца.)
Ответ №3:
Хотя pwrite
это, вероятно, лучшее решение, есть альтернатива, которая придерживается stdio
функций. К сожалению, чтобы сделать его потокобезопасным, вы используете нестандартный « stdio
» для прямого управления FILE*
внутренней блокировкой, а имена не переносимы. В частности, POSIX определяет один набор имен «принять / снять блокировку файла», а Windows определяет другой набор ( _lock_file
/ _unlock_file
).
Тем не менее, вы могли бы использовать эти полупереносимые конструкции для использования stdio
функций для обеспечения отсутствия конфликтов буферизации ( pwrite
to fileno(some_FILE_star)
может вызвать проблемы, если FILE*
буфер перекрывает pwrite
местоположение, поскольку pwrite
не исправит буфер):
// Error checking omitted; you should actually check returns in real code
size_t pfwrite(const void *ptr, size_t size, size_t n,
size_t offset, FILE *stream) {
// Take FILE*'s lock and hold it for entire transaction
flockfile(stream); // _lock_file on Windows
// Record position
long origpos = ftell(stream);
// Seek to desired offset and write
fseek(stream, offset, SEEK_SET); // Possibly offset * size, not just offset?
size_t written = fwrite(ptr, size, n, stream);
// Seek back to original position
fseek(stream, origpos, SEEK_SET);
// Release FILE*'s lock now that transaction complete
funlockfile(stream); // _unlock_file on Windows
return written;
}
Комментарии:
1. Спасибо и за это. Мне не нужна потокобезопасность для этого приложения, но это полезно знать.