繁体   English   中英

如何在C中逐行读取10 GB的txt文件,该文件由制表符分隔的双精度数据组成

[英]How to read a 10 GB txt file consisting of tab-separated double data line by line in C

我有一个txt文件,该文件由制表符分隔的数据(类型为double 数据文件超过10 GB,因此我只希望逐行读取数据,然后进行一些处理。 特别地,数据是作为具有1001列和数百万行的矩阵布置的。 下面只是一个伪造的示例,用于显示布局。

10.2  30.4  42.9 ... 3232.000 23232.45
...
...
7.234  824.23232 ... 4009.23  230.01
...

对于每一行,我想将前1000个值存储在数组中,并将最后一个值存储在单独的变量中。 我是C的新手,如果您能指出主要步骤,那将是很好的。

更新:

感谢您提出的所有宝贵建议和解决方案。 我只是想出一个简单的示例,我只是从txt文件中逐行读取3×4矩阵。 对于每一行,前3个元素存储在x ,最后一个元素存储在向量y 因此xn=p=3 n-by-p矩阵, y1-by-3向量。

以下是我的数据文件和代码。

资料档案:

1.112272    -0.345324   0.608056    0.641006
-0.358203   0.300349    -1.113812   -0.321359
0.155588    2.081781    0.038588    -0.562489

我的代码:

#include<math.h>
#include <stdlib.h>
#include<stdio.h>
#include <string.h>

#define n 3
#define p 3

void main() {

    FILE *fpt;
    fpt = fopen("./data_temp.txt", "r");    

    char line[n*(p+1)*sizeof(double)];
    char *token;
    double *x;
    x = malloc(n*p*sizeof(double));
    double y[n];

    int index = 0;
    int xind = 0;
    int yind = 0;

    while(fgets(line, sizeof(line), fpt)) {
        //printf("%d\n", sizeof(line));
        //printf("%s\n", line);

        token = strtok(line, "\t");
        while(token != NULL) {
            printf("%s\n", token);

            if((index+1) % (p+1) == 0) { // the last element in each line;
                yind = (index + 1) / (p+1) - 1; // get index for y vector;
                sscanf(token, "%lf", &(y[yind]));
            } else {
                sscanf(token, "%lf", &(x[xind]));
                xind++;
            }
            //sscanf(token, "%lf", &(x[index]));
            index++;
            token = strtok(NULL, "\t");
        } 
    }

    int i = 0;
    int j = 0;
    puts("Print x matrix:");
    for(i = 0; i < n*p; i++) {
        printf("%f\n", x[i]);
    }
    printf("\n");

    puts("Print y vector:");
    for(j = 0; j < n; j++) {
        printf("%f\t", y[j]);
    }
    printf("\n");
    free(x);
    fclose(fpt);
}

有了上述内容,如果我用原始的10 GB数据文件替换data_temp.txt (希望在必要时更改np和一些其他代码的值),则希望一切正常。

如果您能帮助我,我还有其他问题。

  1. 我首先将char line[]初始化为char line[(p+1)*sizeof(double)] (注意不要乘n )。 但是该行无法完全读取。 我如何只为一行分配内存? 长度是多少? 我假设它是(p+1)*sizeof(double)因为每行有(p+1) double。 我还应该为\\t\\n分配内存吗? 如果是这样,怎么办?
  2. 代码对您来说看起来合理吗? 由于此代码将在数百万行中执行,因此如何提高效率?
  3. 如果我不知道原始10 GB文件中的列数或行数,如何快速计算行数和列数?

同样,我是C新手,非常感谢任何评论。 非常感谢!

第一种方式

使用fread文件大块读取到预分配的缓冲区中。

第二路

使用mmap将文件映射到您的进程内存空间,然后将指针移到文件上方。

第三种方式

由于文件由行分隔,因此请使用fopen打开文件,使用setvbuf或类似方法将缓冲区大小设置为大约10行左右,然后使用fgets逐行读取文件。

潜在读取文件速度更快,使用openO_DIRECT (假设Linux的),然后用fdopen得到一个FILE *的打开文件,然后使用setvbuf设置页对齐缓冲区。 这样做将允许您绕过内核页面缓存-如果您的系统实现使用直接IO成功地以这种方式工作。 (直接IO可能有很多限制)

入门指南:阅读1行

#define COLUMN (1000+1)
double data[COLUMNS];

for (int i = 0; i< COLUMN; i++) {
  char delim = '\n';
  int cnt = fscanf(in_stream, "%lf%c", &data[i], &delim);
  if (cnt < 1) {
    if (cnt == EOF && i == 0) return 0; // None read, OK as end of file
    puts("Missing or bad data");
    return -1; // problem
  }
  if (delim  != '\t') {
    // If tab not found, should be at end of line
    if (delim  == '\n' && i == COLUMN-1) {
      return COLUMN;  // Success
    } 
    puts("Bad delimiter");
    return -1;
  }
}
puts("Extra data");
return -1;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM