【问题标题】:Fast double file read in C用C快速读取双文件
【发布时间】:2017-04-09 11:57:55
【问题描述】:

我有一个包含浮点数的大文件,我想读取它们。

   52.881 49.779 21.641 37.230 23.417 7.506 120.190 1.240 79.167 82.397 126.502 47.377 112.583 124.590 103.339 5.821 24.566 38.916 42.576 

这只是文件的开始。它有 10000000 个数字。

我得到了这个代码,但我不知道如何打印数字。

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <fcntl.h>
#include <sysexits.h>
#include <unistd.h>

int main()
{
    int fd; 
    size_t bytes_read, bytes_expected = 1000000*sizeof(double); 
    double *data;
    char *infile = "file.dat";

    if ((fd = open(infile,O_RDONLY)) < 0) 
        err(EX_NOINPUT, "%s", infile);

    if ((data = malloc(bytes_expected)) == NULL)
        err(EX_OSERR, "data malloc");

    bytes_read = read(fd, data, bytes_expected);

   if (bytes_read != bytes_expected) 
       err(EX_DATAERR, "Read only %d of %d bytes", 
         bytes_read, bytes_expected);

   /* print all */

   free(data);

   exit(EX_OK);
}

【问题讨论】:

  • 我不需要阅读你的代码来解决问题100000000*sizeof(double),为什么会有这个值?为什么这么大?另外,bytes_read 不一定等于bytes_expected,原因很多,请贴出部分文件内容。
  • 如果你有一个double 的数组,你知道如何打印它吗?数组和指针非常相似,您可以使用相似的语法来访问它们的元素。
  • @zaig 从不使用魔法常数。除非它们像文件格式的标题那样真正具有魔力。
  • 如果文件中的数据是text,你应该把它当作文本而不是二进制数据来读取。改用标准 C 函数(如fopenfscanf 等)
  • 当您在阅读文件方面寻求帮助时,请显示该文件。

标签: c file io


【解决方案1】:

您正在尝试读取文本文件,就好像数据是二进制的一样,因此您将读取一些字节,但存储在数组中的 double 值将不是您想要从文件中读取的值,您可以可能会这样做

FILE *file;
double *array;
size_t count;
const char *infile = "file.dat";

file = fopen(infile, "r");
if (file == NULL)
    return -1;
count = 0;
while (fscanf(file, "%*lf") == 1)
    count += 1;
rewind(file);
array = malloc(count * sizeof(*array));
if (array == NULL) {
    fprintf(stderr, "cannot allocate %zu bytes!\n", count * sizeof(*array));
    fclose(file);
    return -1;
}
// Read the values into the array
for (size_t i = 0; i < count; ++i) {
    fscanf(file, "%lf", &array[i]);
}
// Print the array
for (size_t i = 0; i < count; ++i) {
    fprintf(stdout, "%f\n", array[i]);
}
// Release memory
free(array);

【讨论】:

  • 这是我的第一种方法,但我想尝试一些可能更快的方法
  • 由于问题的标题带有“fast”这个词,我倾向于认为,为了计算数字(通过 1),计算空格可能会更快,但要做到完整的双重扫描。
  • @zaig:如果你有文字(也就是chars),想要doubles,就需要做转换的工作。这不是免费的。它不会在 0 秒内神奇地发生。
  • @zaig:有效的慢代码比无效的快代码要好。
  • @zaig 另外,你不会经常阅读这篇文章吧?因为优化可能是缓存值并避免大量读取它们。
【解决方案2】:

既然您想要一个快速的解决方案,也许您必须牺牲内存。
读取文件更快的方式是二进制形式。
因此,我会用一种有效的方法获得文件大小,
然后我会相应地分配内存,
将整个文件上传到内存的想法。
在那里,由于内存读取比文件读取快,
使用sscanf(...)可以快速读取数据。
我们还可以观察到每个浮点数
需要至少 3 个字符 存储在文本文件中:

  • 1 个字符表示点 ('.'),
  • 1 个字符表示某个数字,
  • 和 1 个字符 在 文件。

因此,文件大小除以 3 将是双精度数组大小的上限。

#include <stdio.h>
int main(void) {
  char *filename = "file.dat";
  FILE *F = fopen(filename, "rb");
  fseek(F, 0L, SEEK_END);
  long int filesize = ftell(F);
  rewind(F);
  char *data = malloc(filesize+1);
  fread(data, filesize, 1, F);
  data[filesize] = '\0';                              // End of string, just in case
  fclose(F);

  // The desired data will be stored in array:  
  double *array = malloc(sizeof(double) * filesize/3);

  int ret;
  int n;       // represents the no chars in a sscanf(...) reading
  double *a = array;
  while (1) {      // Infinite loop...
    ret = sscanf(data, " %lg%n", a, &n);
    if (ret == EOF) break;   // <<---- EXIT POINT of the loop
    a++;
    data += n;
  }

  long int array_size = a - array + 1;
} 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多