我正在尝试从缓冲区文件中读取二进制数据,该文件由不同的进程(我无法修改)连续写入。我正在使用以下代码打开文件:
fileH = CreateFileA((LPCSTR)filename,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
它正确打开,没有错误。但是,当我从文件中读取数据时,似乎阻止了其他进程写入文件,因为我丢失了数据。
缓冲区是循环的,这意味着文件大小是固定的,并且新数据会不断写入缓冲区中的旧数据。
修改 有时最琐碎的解决方案有效......
我已经联系了该软件公司并告诉他们这个错误,并在一天之内发布了一个带有修复程序的新版本。 对不起,这对所有人都不起作用。
答案 0 :(得分:4)
我建议查看优秀Far Manager的源代码。它的内部查看器可以轻松处理数GB的文件,显示正在写入的文件没有问题,几乎可以实时更新更改的文件内容。我从未注意到正在显示的文件存在任何阻塞问题。
与问题相关的源代码似乎位于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调用eventually result。 OVERLAPPED未使用。
答案 1 :(得分:4)
如果不知道写作过程是如何打开文件的话,很难说出你的选择。显然,它不会打开文件进行独占访问并保持打开状态。否则你将无法阅读它。
您描述的行为表明写入过程打开文件以进行独占访问,写入文件,然后关闭文件。如果是这种情况,那么您无法让程序打开文件并保持打开状态。这会导致写入过程在尝试写入时失败。
如果你无法修改写作过程,那么你的选择是有限的,不是很有吸引力。最有可能的是,你必须让程序打开文件,读取一小块文件,关闭文件,然后再等一会儿再读一遍。即使这样,也无法保证在写入过程尝试写入时您不会打开文件。我认为,你已经发现了这一点。
您是否知道写入过程在无法打开文件时是丢失数据,还是只是缓冲数据并在下次实际打开文件时写入数据?如果是这种情况,那么我建议逐步浏览文件可能会有效。否则,你将丢失数据。
我所知道的没有开放模式相当于“打开文件进行阅读,但是如果有人想要独占访问,那就让他们拥有它。”
另一种可能性是让程序在您想要阅读时重命名文件,然后在阅读后删除重命名的文件。当然,这假设写入过程将在必要时创建新文件。即使这样,如果写入过程在您重命名时尝试写入,可能会出现问题。我认为这不是一个问题(就文件系统而言,重命名可能是原子的),但这是你必须研究的东西。