我正在编写一个程序,其中一个进程A读取另一个进程BI附加到文件的数据,使用ReadDirectoryChangesW进行通知。问题是直到我关闭B中的句柄才生成通知,尽管我正在刷新使用fflush将文件内容归档。下面给出了代码
文件编写者:
int _tmain(int argc, _TCHAR* argv[])
{
FILE *fp;
fp=_fsopen("log.txt", "a", _SH_DENYNO);
char str[4096];
for(int i=1;i<4096;i++)
str[i]=i;
while(true){
fwrite(str,1,4096,fp);
fflush(fp);
Sleep(2000);
}
return 0;
}
文件阅读器:
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#include <assert.h>
#include <share.h>
void _tmain(int argc, TCHAR *argv[])
{
FILE *fp;
fp=_fsopen("C:\\Users\\dell\\Documents\\Visual Studio 2012\\Projects\\FileWriter\\FileWriter\\log.txt", "r", _SH_DENYNO);
int last_size=0,new_size=0;
if(fp==NULL)
return ;
HANDLE m_hMonitoredDir = CreateFile(TEXT("C:\\Users\\dell\\Documents\\Visual Studio 2012\\Projects\\FileWriter\\FileWriter"), FILE_LIST_DIRECTORY,
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL );
if ( m_hMonitoredDir == INVALID_HANDLE_VALUE )
{
DWORD dwErr = GetLastError();
printf("error");
return;
}
char szBuf[ MAX_PATH ];
DWORD dwBytesRead = 0;
int flag=0;
char *buffer;
while ( ReadDirectoryChangesW( m_hMonitoredDir, szBuf, MAX_PATH, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE,&dwBytesRead, NULL, NULL ))
{
PFILE_NOTIFY_INFORMATION pstFileNotif = (PFILE_NOTIFY_INFORMATION)( szBuf );
if ( pstFileNotif->Action == FILE_ACTION_MODIFIED )
{
char szNotifFilename[ MAX_PATH ] = { 0 };
if ( int iNotifFilenameLen = WideCharToMultiByte( CP_OEMCP, NULL,
pstFileNotif->FileName,
pstFileNotif->FileNameLength / sizeof( WCHAR ),
szNotifFilename, sizeof( szNotifFilename ) / sizeof( char ),
NULL, NULL ) )
{
if ( strcmp("log.txt", szNotifFilename ) == 0 )
{
fseek(fp, 0, SEEK_END);
new_size = ftell(fp);
fseek(fp,last_size,SEEK_SET);
int size=new_size-last_size;
buffer=new char[size+1];
fread(buffer,1,size,fp);
buffer[size]='\0';
printf("%s",buffer);
free(buffer);
}
}
}
}
}
我可以在B中使用fflush后立即帮助我收到通知吗?
答案 0 :(得分:1)
我不认为这是可能的。根据{{1}} FILE_NOTIFY_CHANGE_LAST_WRITE
(强调我的):
对监视目录或子树中文件的上次写入时间的任何更改都会导致更改通知等待操作返回。 仅当文件写入磁盘时,操作系统才会检测到上次写入时间的更改。对于使用大量缓存的操作系统,只有在缓存充分刷新后才会进行检测。
the documentation确保将文件数据传递回操作系统,但不保证数据写入磁盘,因为通常会涉及大量缓存:
缓冲区通常由操作系统维护,它确定将数据自动写入磁盘的最佳时间:缓冲区已满,流关闭时,或程序正常终止而不关闭流。运行时库的“提交到磁盘”功能可以确保将关键数据直接写入磁盘而不是操作系统缓冲区。
正如其他人在评论中所说,你可能更善于为你的目标使用命名管道,因为你只处理一个已知的文件。
答案 1 :(得分:0)
您可以通过调用_flushall
(http://msdn.microsoft.com/en-us/library/s9xk9ehd.aspx)强制提交到磁盘
或查看本文(http://support.microsoft.com/kb/148505),了解如何强制提交磁盘。您需要与commode.obj
链接以强制fflush
自动提交到磁盘。
替代方法可能是每次fclose
文件,如果你每2秒只做一次(开销很小),则以附加模式重新打开文件。
答案 2 :(得分:0)
参见此处:https://jeffpar.github.io/kbarchive/kb/066/Q66052/
对我们来说,与commode.obj的链接无效。
但是,这种方法确实做到了:
当我们使用fopen打开文件时,我们将“ c”模式选项作为最后一个选项:
fopen( path, "wc") // w - write mode, c - allow immediate commit to disk
然后,当您要强制刷新到磁盘时,调用
_flushall()
我们在致电
之前先打了这个电话fclose()
我们遇到了您所描述的确切问题,并且此方法已将其解决。
从上述网站上
“ Microsoft C / C ++ 7.0版为fopen()引入了” c“模式选项 功能。当应用程序打开文件并指定“ c”模式时, 当运行库将文件缓冲区的内容写入磁盘时, 应用程序调用fflush()或_flushall()函数。 “