我正在编写一个程序来重新格式化DNS日志文件以插入数据库。当前正在写入日志文件的行可能不完整。如果是的话,我想丢弃它。
我开始相信eof
函数可能非常适合我的应用程序,但是我注意到很多程序员劝阻使用eof
函数。我也注意到feof
函数似乎非常相似。
任何关于这些功能的副作用的建议/解释都会受到最多的赞赏,对于更合适的方法的建议也是如此!
修改:我目前正在使用istream::peek
功能,以便跳过最后一行,无论它是否完整。虽然可以接受,但确定最后一行是否完整的解决方案将是首选。
我正在使用的具体比较是:logFile.peek() != EOF
答案 0 :(得分:2)
我会考虑使用
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
如果您尝试使用独占锁打开文件,则可以检测(由于打开失败)文件正在使用中,并在一秒钟内再次尝试...(或随时)
答案 1 :(得分:0)
如果您需要在写入文件时捕获文件内容,那么如果您消除了逻辑与文件中实际数据字节之间的间接层和缓冲层,就会容易得多。
不要使用任何类型的C ++ IO流 - 您无法真正控制它们。不要使用基于FILE *
的函数,例如fopen()
和fread()
- 这些函数是缓冲的,即使您禁用缓冲,代码和数据之间也会有代码层再一次,你无法控制,也不知道发生了什么。
在POSIX环境中,您可以使用低级C风格的open()
和read()
/ pread()
来电。并使用fstat()
了解文件内容何时发生更改 - 在调用st_size
后,您会看到struct stat
参数的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 provides大多数是您的#&# 39; d需要。在Windows上,lseek()
后跟read()
将替换pread()
。