刷新不调用文件更改

Flush not invoking file change

本文关键字:文件 调用 刷新      更新时间:2023-10-16

我正在编写一个程序,其中一个进程 A 读取另一个进程 B 附加到文件的数据。问题是,尽管我使用 fflush 将内容刷新到文件,但在我关闭 B 中的句柄之前不会生成通知。代码如下

文件编写器:

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]='';
                    printf("%s",buffer);
                    free(buffer);
                }
            }
        }
    }
}

任何人都可以帮助我在 B 中使用 fflush 后立即收到通知吗?

我认为这是不可能的。 根据有关FILE_NOTIFY_CHANGE_LAST_WRITE的文档(强调我的(:

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

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

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

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

您可以通过

调用_flushall(http://msdn.microsoft.com/en-us/library/s9xk9ehd.aspx ( 来强制提交到磁盘

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

另一种方法是每次fclose文件,并在追加模式下重新打开文件,如果您每 2 秒只这样做一次(开销很小(。

看这里: 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(( 函数。">