2

我正在编写一个程序,其中一个进程 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 ,谁能帮我收到通知?

4

3 回答 3

1

我不认为这是可能的。根据(强调我的)的文件:FILE_NOTIFY_CHANGE_LAST_WRITE

对监视目录或子树中文件的最后写入时间的任何更改都会导致更改通知等待操作返回。仅当文件写入磁盘时,操作系统才会检测到最后写入时间的更改。对于使用大量缓存的操作系统,仅当缓存被充分刷新时才会进行检测。

fflush()确保将文件数据传递回操作系统,但不保证将数据写入磁盘,因为通常涉及大量缓存:

缓冲区通常由操作系统维护,它决定了将数据自动写入磁盘的最佳时间:缓冲区满时、流关闭时或程序正常终止而不关闭流时。运行时库的提交到磁盘功能使您可以确保将关键数据直接写入磁盘而不是操作系统缓冲区。

正如其他人在评论中所说,您最好使用命名管道来实现您的目标,因为您只处理一个已知文件。

于 2013-09-26T21:41:03.387 回答
0

_flushall您可以通过调用( http://msdn.microsoft.com/en-us/library/s9xk9ehd.aspx )强制提交到磁盘

或查看这篇文章 ( http://support.microsoft.com/kb/148505 ) 如何强制提交到磁盘。您需要链接commode.obj以强制fflush自动提交到磁盘。

另一种方法可能是fclose每次都使用文件,并以附加模式重新打开文件,如果您只每 2 秒执行一次(开销很小)。

于 2013-09-26T21:56:51.367 回答
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() 函数。"

于 2019-07-18T08:05:18.960 回答