Чтение файла во время его записи другим процессом

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

fileH = CreateFileA((LPCSTR)filename,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);

И он открывается правильно, без ошибок. Однако когда я читаю данные из файла, кажется, что другой процесс блокирует запись в файл, поскольку я теряю данные.

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

РЕДАКТИРОВАТЬ:
Иногда самое тривиальное решение работает …

Я связался с компанией-разработчиком программного обеспечения и рассказал им об ошибке, и в течение дня они опубликовали новую версию с исправлением.
Извините, это не может работать для всех.

5

Решение

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

Исходный код, связанный с вопросом, кажется, находится в viewer.cpp файл.

Одна интересная вещь состоит в том, что это не использование GENERIC_READ:

ViewFile.Open(strFileName, FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING);

Я подозреваю сбросить SYNCHRONIZE может быть важно здесь.

Обнаружение изменения файла находится в Viewer::ProcessKey, KEY_IDLE дело:

// Smart file change check -- thanks Dzirt2005
//
bool changed = (
ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime ||
ViewFindData.ftLastWriteTime.dwHighDateTime!=NewViewFindData.ftLastWriteTime.dwHighDateTime ||
ViewFindData.nFileSize != NewViewFindData.nFileSize
);
if ( changed )
ViewFindData = NewViewFindData;
else {
if ( !ViewFile.GetSize(NewViewFindData.nFileSize) || FileSize == static_cast<__int64>(NewViewFindData.nFileSize) )
return TRUE;
changed = FileSize > static_cast<__int64>(NewViewFindData.nFileSize); // true if file shrank
}

Чтение кэшированных файлов реализовано в cache.cpp. Но там нет ничего действительно потрясающего, только некоторые Seek() а также Read() (тот в итоге результат в SetFilePointerEx а также ReadFile Вызовы API). ПЕРЕКРЫТЫЙ не используется.

4

Другие решения

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

Поведение, которое вы описываете, указывает на то, что процесс записи открывает файл для монопольного доступа, выполняет запись в него, а затем закрывает файл. Если это так, то ваша программа не может открыть файл и оставить его открытым. Это может привести к сбою процесса записи при каждой попытке записи.

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

Знаете ли вы, если процесс записи теряет данные, когда он не может открыть файл, или он просто буферизует данные и записывает их в следующий раз, когда он действительно может открыть файл? Если это так, то мое предложение пошагово просмотреть файл может сработать. В противном случае вы потеряете данные.

Я не знаю открытого режима, который бы эквивалентен «Откройте файл для чтения, но если кто-то хочет эксклюзивный доступ, пусть он у него есть».

Другой возможностью было бы заставить вашу программу переименовывать файл всякий раз, когда вы хотите прочитать, а затем удалять переименованный файл после того, как вы его прочитали. Это предполагает, конечно, что процесс записи создаст новый файл при необходимости. Даже тогда, там может быть быть проблемой, если процесс записи пытается написать, пока вы переименовываете. Я не думаю, что это будет проблемой (переименование может быть атомарным в том, что касается файловой системы), но это то, что вам придется исследовать.

4