正在读取可能不完整的文件C++

Reading a Potentially incomplete File C++

本文关键字:文件 C++ 读取      更新时间:2023-10-16

我正在编写一个程序来重新格式化DNS日志文件,以便插入数据库。日志文件中当前写入的行可能不完整。如果是,我想丢弃它。

我开始相信eof函数可能非常适合我的应用程序,但我注意到很多程序员都不赞成使用eof函数。我还注意到feof函数似乎非常相似。

如果你们能提供关于这些功能副作用的任何建议/解释,我们将不胜感激,对于更合适的方法的任何建议也将不胜感激!

编辑:我当前正在使用istream::peek函数跳过最后一行,无论它是否完整。虽然可以接受,但最好是确定最后一行是否完整的解决方案。

我使用的具体比较是:logFile.peek() != EOF

我会考虑使用

int fseek ( FILE * stream, long int offset, int origin );

SEEK_END

然后

long int ftell ( FILE * stream );

以确定文件中的字节数,从而确定文件的结束位置。我发现这在检测文件末尾(以字节为单位)时更可靠。

你能在文件的最后两三个字节中检测到(记录结束/行)EOR标记(可能是CRLF)吗?(3个字节可能用于CRLF^Z…取决于文件类型)。这将验证您是否有完整的最后一行

fseek (stream, -2,SEEK_END);
fread (2 bytes... etc

如果你试图用独占锁打开文件,你可以检测到(通过打开失败)文件正在使用中,然后再试一次。。。(或任何时候)

如果您需要在编写文件时捕获文件内容,那么如果您在逻辑和文件中实际数据字节之间消除尽可能多的间接和缓冲层,则会容易得多。

不要使用任何类型的C++IO流-您无法真正控制它们。不要使用基于FILE *的函数,如fopen()fread(),它们是缓冲的,即使禁用缓冲,代码和数据之间也有代码层,而这些代码层又一次无法控制,也不知道发生了什么。

在POSIX环境中,可以使用低级C样式的open()read()/pread()调用。使用fstat()可以知道文件内容何时发生了更改——您将看到struct stat参数的st_size成员在调用fstat()后发生了更改。

你可以这样打开文件:

int logFileFD = open( "/some/file/name.log", O_RDONLY );

在一个循环中,你可以做这样的事情(省略错误检查和实际数据处理):

size_t lastSize = 0;
while ( !done )
{
    struct stat statBuf;
    fstat( logFileFD, &statBuf );
    if ( statBuf.st_size == lastSize )
    {
        sleep( 1 ); // or however long you want
        continue;   // go to next loop iteration
    }
    // process new data - might need to keep some of the old data
    // around to handle lines that cross boundaries
    processNewContents( logFileFD, lastSize, statBuf.st_size );
}

processNewContents()可能看起来像这样:

void processNewContents( int fd, size_t start, size_t end )
{
    static char oldData[ BUFSIZE ];
    static char newData[ BUFSIZE ];
    // assumes amount of data will fit in newData...
    ssize_t bytesRead = pread( fd, newData, start, end - start );
    // process the data that was read read here
    return;
}

您还可能会发现,您需要向close()添加一些代码,然后重新创建文件open(),以防您的应用程序似乎没有"看到"写入文件的数据。我在一些系统上看到过这种情况——应用程序不知何故在某个地方看到了文件大小的缓存副本,而在另一个上下文中运行的ls则获得了更准确、更新的大小。例如,如果您知道日志文件每10-15秒写入一次,如果您在30秒内没有看到文件的任何更改,请尝试重新打开该文件。

您还可以跟踪struct stat结果中的inode编号,以捕获日志文件旋转。

在非POSIX环境中,您可以用低级别的等效操作系统替换open()fstat()pread()调用,尽管Windows提供了您所需的大部分功能。在Windows上,lseek()read()将取代pread()