首先,您使用的操作系统是什么?如果是Linux,请在
strace
下运行应用程序以查看它实际进行的系统调用。
其次,
fopen() / fseek() / fread()
不适合此访问模式。这些调用缓冲文件读取 - 通过向前读取。这对您没有任何好处。您可以
fseek()
到偏移量X,现在缓冲的任何数据都是无用的,您可以
fread()
100字节,并且缓冲的
fread()
会读取更多 - 可能是8 kB。您几乎在80次内读取文件的每个字节。您可以使用
setbuf()
或
setvbuf()
来禁用缓冲,但然后您将进行100字节的读取,同时向后遍历文件。这应该会更快,但不如您可以去的那么快。
要尽可能快地完成此操作(而不涉及多线程和/或异步IO):
1. 使用
open() / pread()
。您不需要寻找 -
pread()
直接从任意偏移量读取。
2. 读取较大的块 - 比如8192 x 100。或者更大。像之前一样向后读取,但自己进行缓冲并从文件中的偏移量开始,该偏移量是您正在读取的大型大小的倍数 - 第一次读取可能少于819,200字节。首先处理缓冲区中的最后100个字节,然后向后处理缓冲区。当您处理了缓冲区中的前100个字节时,请使用
pread()
从文件中读取以前的819,200个字节(甚至更大)。
3. 如果可用,请使用直接IO。文件系统优化可能会尝试通过向前读取并将数据放入页面高速缓存来“优化”您的访问 - 您已经处理过的数据。因此,如果可能,请绕过页面高速缓存(不是所有操作系统都支持直接IO,也不是在支持直接IO的操作系统上的所有文件系统都实现它)。
类似于这样:
#define DATA_SIZE 100
#define NUM_CHUNKS (32UL * 1024UL)
#define READ_SIZE ( ( size_t ) DATA_SIZE * NUM_CHUNKS )
void processBuffer( const char *buffer, ssize_t bytes )
{
if ( bytes <= 0 ) return;
}
void processFile( const char *filename )
{
struct stat sb;
char *buffer = valloc( READ_SIZE );
int fd = open( filename, O_RDONLY | O_DIRECT );
fstat( fd, &sb );
lldiv_t numReads = lldiv( sb.st_size, READ_SIZE );
if ( numReads.rem )
{
numReads.quot++;
}
while ( numReads.quot > 0 )
{
numReads.quot--;
ssize_t bytesRead = pread( fd, buffer,
READ_SIZE, numReads.quot * READ_SIZE );
processBuffer( buffer, bytesRead );
}
free( buffer );
close( fd );
}
您需要为此添加错误处理。
fseek()
之前,你应该三思而后行。有时它是完成任务的正确工具,但要注意并非所有流都是可寻址的。如果你总是在向后移动/查找恰好100个字节,那么请考虑在内存中缓冲至少这么多的先前数据,以便你不必寻找回去。 - John Bollinger