使用带格式化文本文件的fscanf的问题

时间:2013-12-29 23:09:38

标签: c scanf

我对C / C ++比较陌生,目前(尝试)使用它将包含数字数据的大型格式化文本文件解析成数组,以便能够使用LAPACK库来处理这些文件。登记/> 我正在解析的文本文件有一个非常简单的格式:5行标题后跟50个值,接下来的5行标题和50个值,重复大约约。 100万左右:

5行标题
       1.000000E + 00 2.532093E + 02
       2.000000E + 00 7.372978E + 02
       3.000000E + 00 5.690047E + 02

我目前的方法是使用fscanf函数,但我得到了奇怪的结果。我目前正在使用一种非常天真的方法来跳过包含标题文本的行,但我担心这可能是问题所在。或许我对fscanf的使用存在缺陷。以下是我到目前为止的情况:

int main() {
    FILE *ifp; 
    FILE *ofp;
    char mystring[500];
    int i,j,n;

  //ofp = fopen("newfile.txt","w");
    ifp = fopen("results","r");
    if (ifp != NULL) {
  //Test with 10 result blocks each containing 50 frequency values
    float** A = fmatrix(50,10);
    for (j=0; j<10; j++) {
        //fscanf(ifp, "%*[^\n]\n", NULL);
        //fscanf(ifp, "%*[^\n]\n", NULL);
        //fscanf(ifp, "%*[^\n]\n", NULL);
        //fscanf(ifp, "%*[^\n]\n", NULL);
        //fscanf(ifp, "%*[^\n]\n", NULL);

        //using fgets w/ printf to see contents of "discarded" lines
        fgets(mystring,500,ifp); printf("%s",mystring);
        fgets(mystring,500,ifp); printf("%s",mystring);
        fgets(mystring,500,ifp); printf("%s",mystring);
        fgets(mystring,500,ifp); printf("%s",mystring);
        fgets(mystring,500,ifp); printf("%s",mystring);

        for (i=0; i<50; i++) {
            //skip over first float, store the next float into A[i][j]
            n=fscanf(ifp," %*e %E", &A[i][j]);
            printf("A[%i][%i]: %E, %i\n",i,j,A[i][j],n);
        }
    }
}
return 0;
}

float** fmatrix(int m, int n) {
    //Return an m x n Matrix
    int i;
    float** A = (float**)malloc(m*sizeof(float*));
    A[0] = (float*)malloc(m*n*sizeof(float));
    for (i = 1; i < m; i++) {
        A[i] = A[i-1]+n;
    }
return A;
}  

我得到的结果很奇怪。我得到一个与结果文件匹配的50分量列向量,然后得到50个零作为第二列向量,第三列向量对应于我的结果文件中的第二个值,依此类推。也就是说,我在矩阵中得到交替的零和非零值列。我后来插入了fscanf行以查看发生了什么,令我惊讶的是,一些被丢弃的行是包含数字数据的行,而不仅仅是标题行。

我希望有人可能知道这是什么,或者什么可能是错的?由于这是一个如此简单的格式,我甚至不知道问题可能在哪里。另一个相关的问题是:跳过标题文本的首选方法是什么?我使用的方法实际上只是一次性使用,因为标头/文件格式的任何更改都会使代码变得毫无价值。也许使用fgets检查格式是否与文件的数据部分匹配,并跳过任何与2列模式不匹配的行?

关于表现的最后一个问题:除了错误之外,fscanf是最好的方式来进行吗?正如我之前提到的,这些文件有时可能有几亿行的大小,而且我不熟悉C / C ++,知道是否有更快的方法将大量的行读入矩阵/向量。

我希望我在这里提供了足够的信息来澄清我的问题。如果需要,我可以在这里发布我的结果文件的摘录。

1 个答案:

答案 0 :(得分:1)

因为您没有始终使用fgets(),所以您会读取5个标题行,然后是50个数字,但最后一个数字会在第55行留下换行,以供第一个fgets()或下一个标题行块。所以第二个标题读取块读取换行符(仅),然后读取4个标题行,然后数据扫描尝试读取标题的最后一行作为数字并且(可能)失败。

始终检查每个输入功能的返回值(即使它似乎让生活变得痛苦)。

而且,我建议,使用fgets()来读取每一行。略过标题行;使用sscanf()转换数据行上的数据。但请检查fgets()sscanf()以获取正确的返回值。 还有其他功能可以将字符串转换为数字;可以使用strtod()

这里有一些工作代码,减少了5个数据块,每组10行(还有5个标题行):

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

extern float **fmatrix(int m, int n);

enum { HDRS = 5, ROWS = 10, COLS = 5 };

static int read_line(FILE *ifp, char *buffer, size_t buflen)
{
    if (fgets(buffer, buflen, ifp) == 0)
    {
        fprintf(stderr, "EOF\n");
        return 0;
    }
    size_t len = strlen(buffer);
    buffer[len-1] = '\0';
    printf("[[%s]]\n", buffer);
    return 1;
}

int main(void)
{
    FILE *ifp;
    char mystring[500];
    int i, j, n;

    ifp = stdin;
    if (ifp != NULL)
    {
        // Test with COLS result blocks each containing ROWS frequency values
        float **A = fmatrix(ROWS, COLS);
        for (j = 0; j < COLS; j++)
        {
            // using fgets w/ printf to see contents of "discarded" lines
            for (i = 0; i < HDRS; i++)
            {
                if (read_line(ifp, mystring, sizeof(mystring)) == 0)
                    break;
            }

            for (i = 0; i < ROWS; i++)
            {
                // skip over first float, store the next float into A[i][j]
                if (read_line(ifp, mystring, sizeof(mystring)) == 0)
                    break;
                if ((n = sscanf(mystring, " %*e %E", &A[i][j])) != 1)
                    break;
                printf("A[%i][%i]: %E, %i\n", i, j, A[i][j], n);
            }
        }

        for (i = 0; i < ROWS; i++)
        {
            for (j = 0; j < COLS; j++)
                printf("%8.3f", A[i][j]);
            putchar('\n');
        }
    }
    return 0;
}

float **fmatrix(int m, int n)
{
    // Return an m x n Matrix
    int i;
    float **A = (float **)malloc(m * sizeof(float *));
    A[0] = (float *)malloc(m * n * sizeof(float));
    for (i = 1; i < m; i++)
    {
        A[i] = A[i - 1] + n;
    }
    return A;
}

较小的数据文件:

Line 1 of heading 1
Line 2 of heading 1
Line 3 of heading 1
Line 4 of heading 1
Line 5 of heading 1
18.1815 56.4442
12.0478 15.5530
47.7793 44.5291
30.8319 78.9396
53.5651 28.1290
74.9131 90.5912
34.9319 10.5254
69.7780 56.8633
92.5056 11.8101
82.0158 31.7586
Line 1 of heading 2
Line 2 of heading 2
Line 3 of heading 2
Line 4 of heading 2
Line 5 of heading 2
118.15 564.442
104.78 155.530
477.93 445.291
383.19 789.396
556.51 281.290
791.31 905.912
393.19 105.254
677.80 568.633
950.56 118.101
801.58 317.586
Line 1 of heading 3
Line 2 of heading 3
Line 3 of heading 3
Line 4 of heading 3
Line 5 of heading 3
18.1815 36.4442
12.0478 35.5530
47.7793 34.5291
30.8319 38.9396
53.5651 38.1290
74.9131 30.5912
34.9319 30.5254
69.7780 36.8633
92.5056 31.8101
82.0158 31.7586
Line 1 of heading 4
Line 2 of heading 4
Line 3 of heading 4
Line 4 of heading 4
Line 5 of heading 4
118.15 464.442
104.78 455.530
477.93 445.291
383.19 489.396
556.51 481.290
791.31 405.912
393.19 405.254
677.80 468.633
950.56 418.101
801.58 417.586
Line 1 of heading 5
Line 2 of heading 5
Line 3 of heading 5
Line 4 of heading 5
Line 5 of heading 5
118.15 564.442
104.78 555.530
477.93 545.291
383.19 589.396
556.51 581.290
791.31 505.912
393.19 505.254
677.80 568.633
950.56 518.101
801.58 517.586

请注意,以不同方式编辑了20个随机数的块,以便在每个块中获得不同的数字。但是,这些区块中的值之间存在着强烈的遗传相似性。

在数据文件上运行程序的结果。

[[Line 1 of heading 1]]
[[Line 2 of heading 1]]
[[Line 3 of heading 1]]
[[Line 4 of heading 1]]
[[Line 5 of heading 1]]
[[18.1815 56.4442]]
A[0][0]: 5.644420E+01, 1
[[12.0478 15.5530]]
A[1][0]: 1.555300E+01, 1
[[47.7793 44.5291]]
A[2][0]: 4.452910E+01, 1
[[30.8319 78.9396]]
A[3][0]: 7.893960E+01, 1
[[53.5651 28.1290]]
A[4][0]: 2.812900E+01, 1
[[74.9131 90.5912]]
A[5][0]: 9.059120E+01, 1
[[34.9319 10.5254]]
A[6][0]: 1.052540E+01, 1
[[69.7780 56.8633]]
A[7][0]: 5.686330E+01, 1
[[92.5056 11.8101]]
A[8][0]: 1.181010E+01, 1
[[82.0158 31.7586]]
A[9][0]: 3.175860E+01, 1
[[Line 1 of heading 2]]
[[Line 2 of heading 2]]
[[Line 3 of heading 2]]
[[Line 4 of heading 2]]
[[Line 5 of heading 2]]
[[118.15 564.442]]
A[0][1]: 5.644420E+02, 1
[[104.78 155.530]]
A[1][1]: 1.555300E+02, 1
[[477.93 445.291]]
A[2][1]: 4.452910E+02, 1
[[383.19 789.396]]
A[3][1]: 7.893960E+02, 1
[[556.51 281.290]]
A[4][1]: 2.812900E+02, 1
[[791.31 905.912]]
A[5][1]: 9.059120E+02, 1
[[393.19 105.254]]
A[6][1]: 1.052540E+02, 1
[[677.80 568.633]]
A[7][1]: 5.686330E+02, 1
[[950.56 118.101]]
A[8][1]: 1.181010E+02, 1
[[801.58 317.586]]
A[9][1]: 3.175860E+02, 1
[[Line 1 of heading 3]]
[[Line 2 of heading 3]]
[[Line 3 of heading 3]]
[[Line 4 of heading 3]]
[[Line 5 of heading 3]]
[[18.1815 36.4442]]
A[0][2]: 3.644420E+01, 1
[[12.0478 35.5530]]
A[1][2]: 3.555300E+01, 1
[[47.7793 34.5291]]
A[2][2]: 3.452910E+01, 1
[[30.8319 38.9396]]
A[3][2]: 3.893960E+01, 1
[[53.5651 38.1290]]
A[4][2]: 3.812900E+01, 1
[[74.9131 30.5912]]
A[5][2]: 3.059120E+01, 1
[[34.9319 30.5254]]
A[6][2]: 3.052540E+01, 1
[[69.7780 36.8633]]
A[7][2]: 3.686330E+01, 1
[[92.5056 31.8101]]
A[8][2]: 3.181010E+01, 1
[[82.0158 31.7586]]
A[9][2]: 3.175860E+01, 1
[[Line 1 of heading 4]]
[[Line 2 of heading 4]]
[[Line 3 of heading 4]]
[[Line 4 of heading 4]]
[[Line 5 of heading 4]]
[[118.15 464.442]]
A[0][3]: 4.644420E+02, 1
[[104.78 455.530]]
A[1][3]: 4.555300E+02, 1
[[477.93 445.291]]
A[2][3]: 4.452910E+02, 1
[[383.19 489.396]]
A[3][3]: 4.893960E+02, 1
[[556.51 481.290]]
A[4][3]: 4.812900E+02, 1
[[791.31 405.912]]
A[5][3]: 4.059120E+02, 1
[[393.19 405.254]]
A[6][3]: 4.052540E+02, 1
[[677.80 468.633]]
A[7][3]: 4.686330E+02, 1
[[950.56 418.101]]
A[8][3]: 4.181010E+02, 1
[[801.58 417.586]]
A[9][3]: 4.175860E+02, 1
[[Line 1 of heading 5]]
[[Line 2 of heading 5]]
[[Line 3 of heading 5]]
[[Line 4 of heading 5]]
[[Line 5 of heading 5]]
[[118.15 564.442]]
A[0][4]: 5.644420E+02, 1
[[104.78 555.530]]
A[1][4]: 5.555300E+02, 1
[[477.93 545.291]]
A[2][4]: 5.452910E+02, 1
[[383.19 589.396]]
A[3][4]: 5.893960E+02, 1
[[556.51 581.290]]
A[4][4]: 5.812900E+02, 1
[[791.31 505.912]]
A[5][4]: 5.059120E+02, 1
[[393.19 505.254]]
A[6][4]: 5.052540E+02, 1
[[677.80 568.633]]
A[7][4]: 5.686330E+02, 1
[[950.56 518.101]]
A[8][4]: 5.181010E+02, 1
[[801.58 517.586]]
A[9][4]: 5.175860E+02, 1
  56.444 564.442  36.444 464.442 564.442
  15.553 155.530  35.553 455.530 555.530
  44.529 445.291  34.529 445.291 545.291
  78.940 789.396  38.940 489.396 589.396
  28.129 281.290  38.129 481.290 581.290
  90.591 905.912  30.591 405.912 505.912
  10.525 105.254  30.525 405.254 505.254
  56.863 568.633  36.863 468.633 568.633
  11.810 118.101  31.810 418.101 518.101
  31.759 317.586  31.759 417.586 517.586