Хранение огромного массива в файле строка за строкой приводит к повреждению файла - PullRequest
2 голосов
/ 05 апреля 2020

У меня есть входной массив A, хранящийся в памяти, который используется для создания другого массива, намного большего B. Однако, поскольку B - это огромный массив, я не хочу хранить его в памяти, но сохранить его локально в файл (используя fwrite). Для этого я вычисляю каждую итерацию строки i th и добавляю ее в выходной файл. Таким образом, мне нужно хранить только одну строку за раз в памяти, и, в конце концов, создается выходной файл со всеми необходимыми мне данными.

Кажется, что выходной файл имеет правильный размер, учитывая количество предметов, из которых оно состоит. Тем не менее, когда я пытаюсь прочитать фрагменты из выходного файла, используя fread (например, получить первые 2000 элементов), получаются только первые 23 элемента.

Это основная функция для создания выходной файл:

void exportCovMatrix(char *outputString, double *inputStdMatrix, int colDim, int rowDim) {
    double *covRow = calloc(rowDim, sizeof(double));
    int i, j, n;
    FILE *output;
    fclose(fopen(outputString, "w"));
    output = fopen(outputString, "a");
    assert(covRow != NULL);
    assert(output != NULL);
    for (i = 0; i < rowDim; i++) {
        for (j = 0; j < rowDim; j++)
            covRow[j] = dotProduct(&inputStdMatrix[i * colDim], &inputStdMatrix[j * colDim], colDim);
        n = fwrite(covRow, sizeof(double), rowDim, output);
        assert(n == rowDim);
    }
    fclose(output);
    free(covRow);
}

Это еще одна функция, которая читает указанный выходной файл:

double *calculateNextB(char* inputString, double* row, int dim){
    FILE* input = fopen(inputString, "r");
    int i, j;
    assert(input != NULL);
    for(i = 0; i <= dim; i++){
        j = fread(row, sizeof(double), dim, input);
        printf("%d items were read.\n", j);
    }
    ...
}

Буду признателен за любую помощь в решении этой проблемы. Спасибо!

Ответы [ 3 ]

2 голосов
/ 05 апреля 2020

Я бы предположил, что файл действительно большой.

В 32-битной системе функции, связанные с потоком (fopen, fwrite и т. Д. c.), Ограничены 2 ГБ. При превышении этого размера влияние функций не определяется.

Пожалуйста, обратитесь к этой странице.

https://www.gnu.org/software/libc/manual/html_node/Opening-Streams.html#index-fopen64-931

Также обратитесь к этому вопросу.

2 голосов
/ 05 апреля 2020

Вы открываете файл соответственно с помощью

fclose(fopen(outputString, "w"));

и

FILE* input = fopen(inputString, "r");

Но, как объяснено, например, здесь

В Чтобы открыть файл как двоичный файл, в строку режима должен быть включен символ «b».

(я знаю, что это источник C ++, но в некоторых системах это правда, хотя это не во многих системах POSIX, как объяснено в https://linux.die.net/man/3/fopen)

1 голос
/ 07 апреля 2020

относительно этого (слегка измененного) предложенного кода:

  1. , который правильно проверяет ошибки
  2. , избегает использования assert() в (возможно) производственном коде
  3. вычисляет каждую строку данных, а затем записывает эту строку в файл.
  4. устанавливает размер файла обратно равным 0 длине при каждом вызове этой функции.
  5. правильно указывает, что файл является двоичным 'file, а не' text 'file.
  6. не компилируется из-за' Ничего 'для функции: dotproduct()
  7. не знает длину каждой строки в inputStdMatrix[ rowDim ][ colDim ]
  8. и этот параметр не следует: double *inputStdMatrix записывать в виде: double inputStdMatrix[][ colDim ] с параметрами rowDim и colDim перед этим параметром
  9. правильно ограничивает «область действия» локального переменные

А теперь предложенный код:

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


void exportCovMatrix(char *outputString, size_t colDim, size_t rowDim, double inputStdMatrix[][ colDim ], ) 
{
    double *covRow = calloc(rowDim, sizeof(double));
    if( ! covRow )
    {
        perror( "calloc for row of data failed" );
        exit( EXIT_FAILURE );
    }

    FILE *output;
    output = fopen(outputString, "wb");
    if( ! output )
    {
        perror( "fopen for write binary file failed" );
        free( covRow );  // cleanup
        exit( EXIT_FAILURE );
    }

    // assert(covRow != NULL);
    // assert(output != NULL);

    for ( size_t i = 0; i < rowDim; i++) 
    {
        for ( size_t j = 0; j < rowDim; j++)
        {
            covRow[j] = dotProduct(&inputStdMatrix[i * colDim],
                                   &inputStdMatrix[j * colDim], 
                                    colDim);
        }

        size_t n = fwrite(covRow, sizeof(double), rowDim, output);
        // assert(n == rowDim);
        if( n != rowDim )
        {
            // handle error of short write
        }
    }

    fclose(output);
    free(covRow);
}

, который записывает в файл только rowDim строк.

Затем, если он вызывается снова , он стирает то, что было в файле. вероятно, не то, что вы хотите.

...