2

我可以在这段代码上使用一组(或更多)眼睛。我正在尝试从文件流(f1)读取一定数量的字节到数组/缓冲区(文件是文本文件,数组是 char 类型)。如果我读取大小“缓冲区 - 1”,我想“重新分配”数组并继续读取,从我离开的地方开始。基本上我正在尝试为未知大小的文件动态扩展缓冲区。我想知道的是:

  1. 我执行这个错误吗?
  2. 我将如何使用代码检查诸如“realloc”之类的故障条件?
  3. 当我编译关于“内置函数 realloc 的隐式声明......”时,我收到了很多警告(我也看到了关于我使用 read、malloc、strlen 等的警告。
  4. 当第二次(以及第三次、第四次等)调用“read()”时,它是否每次都从流的开头读取?那可能是我的问题是我似乎只返回第一个“buff_size”字符。

这是片段:

//read_buffer is of size buff_size
n_read = read(f1, read_buffer, buff_size - 1);
read_count = n_read;
int new_size = buff_size;
while (read_count == (buff_size - 1))
{

        new_size *= 2;
        read_buffer = realloc(read_buffer, new_size);
        n_read = read(f1, read_buffer[read_count], buff_size - 1);
        read_count += n_read;
}

当我正在学习如何进行这种类型的动态阅读时,我想知道是否有人可以陈述一些关于这种事情的最佳实践的简短事实。我假设这在专业领域出现了 TON(读取未知大小的文件)?谢谢你的时间。ALSO:当你们找到了做事的好方法(即解决此类问题的技术)时,您是否发现自己记住了您是如何做到的,或者可能将其保存以供将来参考(即解决方案相当静态)?

4

3 回答 3

6

如果您要扩展整个文件的缓冲区,最简单的方法可能是搜索到最后,获取当前偏移量,然后再搜索到开头并一举读取:

size = lseek(f1, 0, SEEK_END); // get offset at end of file

lseek(f1, 0, SEEK_SET); // seek back to beginning

buffer = malloc(size+1); // allocate enough memory.

read(f1, buffer, size);  // read in the file

或者,在任何相当现代的类似 POSIX 的系统上,考虑使用mmap.

于 2012-05-02T19:00:48.993 回答
2

这是一个很酷的技巧:使用mmap(man mmap)。

简而言之,假设你有你的文件描述符f1,在一个nb字节文件上。你只需调用

char *map = mmap(NULL, nb, PROT_READ, MAP_PRIVATE, f1, 0);
if (map == MAP_FAILED) {
    return -1; // handle failure
}

完毕。

您可以从文件中读取,就好像它已经在内存中一样,操作系统会根据需要将页面读入内存。完成后,您可以简单地调用

munmap(map, nb);

并且映射消失了。

编辑:我刚刚重新阅读了您的帖子,发现您不知道文件大小。为什么?

您可以使用lseek查找文件末尾并了解其当前长度。

相反,如果是因为其他人在您阅读时正在写入文件,您可以从当前映射中读取直到它用完,然后lseek再次调用以获取新长度,并使用mremap来增加大小。或者,您可以简单地使用munmap您拥有的东西,并mmap使用新的“偏移量”(我设置为 0 的数字,即要跳过文件的多少字节)。

于 2012-05-02T19:00:18.730 回答
2
#include <stdlib.h> /* for realloc() */
#include <string.h> /* for memcpy() */
#include <unistd.h> /* for read() */

char buff[512] ; /* anything goes */
size_t done, size;
char *result = NULL;
int fd;

done = size = 0;
while (1) {
        int n_read;
        n_read = read(fd, buff, sizeof buff);
        if (n_read <=0) {
            ... for network connections, (n_read == -1 && errno == EAGAIN)
            ... should be handled special (by a continue) here.
            break;
            }
        if (done+n_read > size) {
            result = realloc(result, size ? 2*size : n_read );
            ... maybe handle NULL return from realloc here ...
            size = size ? 2*size : n_read;
            }
        memcpy(result+done, buff, n_read);
        done += n_read;
        }
 ... and maybe shave down result a bit here ...

注意:这或多或少是香草的方式。另一种方法是首先 malloc 一个真正的大数组,然后再重新分配到正确的大小。这将减少重新分配的数量,并且对于 malloc 领域,wrt 碎片可能更温和。YMMV。

于 2012-05-02T19:12:02.657 回答