C语言 伺机读取磁盘



在Linux中,我如何实现一个函数(或直接系统调用),它将:

  • 阻塞,直到从普通文件(在本地磁盘上,而不是连接到网络设备的"文件")和
  • 读取至少一些最小字节数(32或4,096)。当
  • 返回时,提供当前可用的尽可能多的字节(立即,没有进一步阻塞),最多传递的缓冲区大小(32 MiB)?

read:

  • 如果没有可用的数据,则等待,直到有可用的数据。

  • 如果/当有可用的数据时,它返回所有可用的数据,不超过指定的量。

例如,假设您希望读取至少4kib的数据,而您要求读取64kib的数据。如果有8 KiB可用,read将立即返回这8 KiB。(它不会等待另外56千兆美元的到来。)

同样,如果最初只有2kib可用,read将返回该值。没有办法告诉系统等待,直到4kib可用。因此,这意味着如果我们想获得最小的数量,我们需要调用read

ssize_t read_min( int fd, void *buf, size_t max_to_read, size_t min_to_read ) {
if ( min_to_read > SSIZE_MAX )
min_to_read = SSIZE_MAX;
if ( max_to_read > SSIZE_MAX )
max_to_read = SSIZE_MAX;

size_t total_read = 0;
while ( total_read < min_to_read ) {
ssize_t bytes_read = read( fd, buf + total_read, max_to_read );
if ( bytes_read < 0 )
return -1;
if ( bytes_read == 0 )
return total_read;
max_to_read -= bytes_read;
total_read  += bytes_read;
}
return total_read;
}

或者,您可以在文件描述符上使用阻塞调用select()

  • 我们假设文件是不断写入的,如日志文件或cdr文件。
  • 当你没有在select()调用中指定timeout时,它会阻塞,直到文件描述符可用来读/写,只是在我们的情况下读。
  • 使用FD_SET设置fd,使select()等待,直到准备好读取。
  • select返回时,验证fd是否确实准备好使用FD_ISSET宏读取。
  • 重复上述步骤,直到您读取了足够的数据以满足您的要求。

这是sockets中常用的方法,用于读取头/类型值后面的预期负载/数据。

// assumes buf_sz > read_min
ssize_t read_min (const int fd, void *buf, size_t buf_sz, size_t read_min) {
if (buf_sz > SSIZE_MAX) buf_sz = SSIZE_MAX;
if (read_min > buf_sz) read_min = buf_sz;
ssize_t total = 0;
ssize_t bytes_read = 0;
while (total < read_min) {
fd_set rfds;
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
int status = select (fd + 1, &rfds, NULL, NULL, NULL); // blocking call
if (-1  == status)
perror ("read_min-select()");
if (FD_ISSET (fd, &rfds)) {
bytes_read = read (fd, buf + total, buf_sz - total);
if (bytes_read > 0)
total  += bytes_read;
if (bytes_read < 0)
perror ("read_min-read()");
/* if (0 == bytes_read) // EOF, do you want to return here?
return total;
*/
}
}
return total;
}

没有标准函数可以做我认为你在问的事情:

  • 执行读取阻塞,直到它传输至少n字节,其中n>1,然而
  • 最多读取n字节,如果它可以这样做而不阻塞比获取n字节所需的更多。

您可以在read()之上构建自己的。read()是一个很好的选择,因为(默认情况下使用阻塞I/O)它可以满足n== 1的情况。因此,如果您只是在同一个缓冲区中执行read()s,直到您总共传输了至少n字节,或者到达文件的末尾或发生错误,那么总体结果就是您所描述的。像这样:

ssize_t read_min(int fd, void *buf, size_t buf_size, size_t min_to_read) {
ssize_t total_read = 0;
ssize_t nread;
do {
n_read = read(fd, buffer + total_read, buf_size - total_read);
} while (nread > 0 && total_read < min_to_read);
return (nread < 0) ? -1 : total_read;
}

最新更新