c - 使用c在linux上以 block 的形式读写

标签 c linux

我有一个 ASCII 文件,其中每一行都包含一个可变长度的记录。例如

Record-1:15 characters
Record-2:200 characters
Record-3:500 characters
...
...
Record-n: X characters

由于文件大小约为 10GB,我想分 block 读取记录。一旦读取,我需要转换它们,将它们以二进制格式写入另一个文件。

所以,为了阅读,我的第一 react 是创建一个字符数组,例如

FILE *stream; 
char buffer[104857600]; //100 MB char array
fread(buffer, sizeof(buffer), 104857600, stream);
  1. 假设 linux 将发出一个系统调用并获取整个 100MB 是否正确?
  2. 由于记录由换行符分隔,我在缓冲区中逐个字符地搜索换行符并重建每条记录。

我的问题是,这是我应该如何分 block 读取,或者是否有更好的替代方法来分 block 读取数据并重建每条记录?是否有另一种方法可以在一次调用中从 ASCII 文件中读取 x 条可变大小的行?

接下来在写入期间,我也这样做。我有一个写入字符缓冲区,我将其传递给 fwrite 以在一次调用中写入一整套记录。

fwrite(buffer, sizeof(buffer), 104857600, stream);

更新:如果我设置 buf(stream, buffer),其中 buffer 是我的 100MB 字符缓冲区,fgets 会从缓冲区返回还是导致磁盘 IO?

最佳答案

  1. 是的,fread 会一次获取全部内容。 (假设它是一个普通文件。)但它不会读取 105 MB,除非文件本身是 105 MB,如果您不检查返回值,您将无法知道实际读取了多少数据,或者是否有是一个错误。

  2. 使用 fgets(参见 man fgets)代替 fread。这将为您搜索换行符。

    char linebuf[1000];
    FILE *file = ...;
    while (fgets(linebuf, sizeof(linebuf), file) {
        // decode one line
    }
    
  3. 您的代码有问题。

    char buffer[104857600]; // too big
    

    如果您尝试在堆栈上分配一个大缓冲区(105 MB 肯定很大),那么它将失败并且您的程序将崩溃。如果您需要那么大的缓冲区,则必须使用 malloc 或类似方法在堆上分配它。我肯定会将单个函数的堆栈使用量保持在最多几十 KB,尽管在大多数普通 Linux 系统上您可能会使用几 MB。

作为替代方案,您可以将整个文件mmap 到内存中。在大多数情况下,这不会提高或降低性能,但更易于使用。

int r, fdes;
struct stat st;
void *ptr;
size_t sz;

fdes = open(filename, O_RDONLY);
if (fdes < 0) abort();
r = fstat(fdes, &st);
if (r) abort();
if (st.st_size > (size_t) -1) abort(); // too big to map
sz = st.st_size;
ptr = mmap(NULL, sz, PROT_READ, MAP_SHARED, fdes, 0);
if (ptr == MAP_FAILED) abort();
close(fdes); // file no longer needed

// now, ptr has the data, sz has the data length
// you can use ordinary string functions

使用mmap 的好处是您的程序不会耗尽内存。在 64 位系统上,您可以将整个文件同时放入您的地址空间(即使是 10 GB 的文件),系统会在您的程序访问内存时自动读取新的 block 。旧 block 将被自动丢弃,并在您的程序再次需要它们时重新读取。

这是浏览大文件的一种非常好的方式。

关于c - 使用c在linux上以 block 的形式读写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10527187/

相关文章:

c - 发生错误后是否必须释放任何先前分配的内存?

c - 将输出延迟到 EOF 而不是换行符

linux - 在不使用unix中的排序的情况下对字符进行排序

linux - 我有一个apache软件版本的文件记录,需要根据版本对它们进行排序

linux - 从 CRON 开始使用 xvfb 虚拟显示器进行测试 - 缺少键盘设备

c - 为什么显示从 s1->top 开始?

c - 在 C 中,给定一个可变参数列表,如何使用它们构建函数调用?

c - 如何使用 fork() 从 child 创建子进程?

c++ - 无法在 Linux 上运行 BRIEF_demo

linux - 并行脚本中的 Bash 重定向