2017-02-14 32 views
1

Я пытаюсь использовать fread и fwrite для чтения и записи данных, относящихся к структуре в файле. Вот мой код:Проблемы с чтением из файла после его записи и его закрытия в c

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

typedef struct book book; 

struct book 
{ 
char title[200]; 
char auth[200]; 
char publi[200]; 
int p_year; 
int price; 
int edition; 
int isbn; 
}; 

int main() 
{ 
    int i; 
    FILE* fp = fopen("this.dat","w"); 
    book * a = calloc(1000000,sizeof (book)); 

    srand(time(NULL)); 

    for(i=0;i<1000000;i++) 
    { 
     a[i].price = rand()%1000; 
     a[i].p_year = 1500 + rand()%518; 
     a[i].isbn = 10000+rand()%100000; 
     a[i].edition = i%15; 

     strcpy(a[i].title,"title"); 
     strcpy(a[i].auth,"author"); 
     strcpy(a[i].publi,"publication"); 
    } 

    if((i=fwrite(a,sizeof(*a),1000000,fp))!= 1000000) 
    { 
     printf("ERROR - Only %d records written\n",i); 
     printf("feof:%d\nferror:%d",feof(fp),ferror(fp)); 
     return EXIT_FAILURE; 
    } 

    if(ferror(fp)) 
    { 
     printf("ERROR"); 
     return EXIT_FAILURE; 
    } 

    if(fclose(fp)!=0) 
    { 
     printf("ERROR while closing the stream"); 
     return EXIT_FAILURE; 
    } 

    if((fp = fopen("this.dat","r")) == NULL) 
    { 
     printf("ERROR reopening"); 
     return EXIT_FAILURE; 
    } 

    if((i=fread(a,sizeof(book),100,fp))!=100) 
    { 
     printf("ERROR - Only %d records read\n",i); 
     printf("feof:%d\nferror:%d",feof(fp),ferror(fp)); 
     return EXIT_FAILURE; 
    } 

    if(ferror(fp)) 
    { 
     printf("~ERROR"); 
     return EXIT_FAILURE; 
    } 

    for(i=0;i<100;i++) 
     printf("price:%d\nedition:%d\nisbn:%d\np_year:%d\n\n\n",a[i].price,a[i].edition,a[i].isbn,a[i].p_year); 


    fclose(fp); 
    return EXIT_SUCCESS; 
    } 

Дело в том, что иногда это выполняется успешно, но в большинстве случаев это не так. Я получаю сообщение об ошибке при чтении из файла с помощью fread. Он заканчивает чтение переменной количества записей каждый раз и меньшее количество записей, чем предполагалось (т.е. 100). Ниже приводится один из выходов неудачного выполнения программы:

ERROR - только 25 записей чтения
feof: 16
FERROR: 0

Вопрос 1: Почему ВФ достигается чтение только 25 записей, когда было написано более 25? (я попытался с помощью rewind/fseek после повторного открытия файла, но проблема все еще сохраняется.)

Вопрос 2: В таких случаях, это нормально для данных, содержащихся в массиве a за a[x-1], чтобы получить подменяется, когда x (< 100) записи прочитаны? Будут ли данные по-прежнему изменяться за пределами a[99], даже если 100 записей были успешно прочитаны? (я знаю, что получает данные подделаны, так как пытается напечатать поля элементов массива a за пределы результатов xth элементов в неподходящих значений, как цена> 1000 или цена < 0 и так далее)

+0

Вы на окнах за один шанс? –

+0

Да Я на окнах с gcc 4.9.3 – subzero

+0

Пожалуйста, попробуйте еще раз прочитать. Будете ли вы получить еще 25 записей? – Arkadiy

ответ

1

не следует открывать ваши файлы в текстовом режиме при чтении/записи в виде двоичных структур.

Принимая во внимание, что это не влияет на Linux/Unix, в Windows это имеет серьезные последствия. И это делает ваши файлы несовместимыми между Windows и Linux.

В зависимости от LF данных < => CR/преобразование LF может привести к потере/сдвиг данных (удаление возврат каретки или вставки одного)

в текстовом режиме в Windows, каждый LF (ASCII 10) байт заменяется по CR + LF (13 + 10 ASCII) байтам при записи (и наоборот при чтении: 13 + 10 => 10). Эти 10 байтов могут произойти, например, при записи года 1802 (hex: 0x70A) в виде двоичного файла.

Решение: использовать бинарный режим:

if((fp = fopen("this.dat","rb")) == NULL) 

и

FILE* fp = fopen("this.dat","wb"); 

Примечание: В режиме «текст», указав размер блока не работает, так как размер зависит от данных. Вероятно, это отвечает на ваш второй вопрос: последняя 100-я запись чтения повреждена, потому что вы читаете слишком мало байтов. Я не уверен в деталях, но поскольку система добавляет/удаляет байты при записи/чтении, размер блока может быть недостаточным.

+0

Хотя это работает, я не питаюсь нигде в любом месте файла, так что вы уверены, что это преобразование является проблемой здесь?Также, когда я открываю его в режиме «w +» и не закрываю его и снова открываю, а просто перематываю, а затем читаю, он работает нормально! Так что закрытие и повторное открытие подразумевают какую-то проблему? например, возможно, проблема с маркировкой eof в файле или что-то в этом роде? – subzero

+0

Вы пишете в своем пространстве Dropbox случайно? –

+0

Если вы имеете в виду Dropbox, то нет! – subzero