C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Защита чтения из файла, Проблеммы при повреждении файла
Vasily
  Отправлено: 09.02.2005, 12:18


Дежурный стрелочник

Группа: Участник
Сообщений: 31



Подскажите как защитить чтение из файла.
Задача следующая:
Динамический массив char* необходимо положить в файл.
Реализация:
Вначале в файл кладу кол-во элементов массива,
затем сами char* (соответственно значения, а не адреса)smile.gif
При чтении все нормально работает.
Но если файл поврежден, то соответственно все рушится.
Вопрос:
Как защитить чтение из файла, чтобы просто прерывалось чтение с сообщением о повреждении файла с возможностью продолжать выполнение программы.

Guest
Отправлено: 09.02.2005, 12:25


Не зарегистрирован







А что, try catch не помогает?
Gedeon
Отправлено: 09.02.2005, 12:51


Ветеран

Группа: Модератор
Сообщений: 1742



Вы бы код привели как пишите и читаете, ато как-то догадываться не очень получается.
Vasily
Отправлено: 09.02.2005, 14:17


Дежурный стрелочник

Группа: Участник
Сообщений: 31



CODE

int Mess::SaveToFile(AnsiString f)
{
if(!Counts)return 0;
unsigned it=0;
unsigned tmp=0;
Mess* Save=Begin;
FILE* F;
if((F=fopen(f.c_str(),"wb"))==0) return 0;
fwrite(&Counts,sizeof(int),1,F);
do
{
it=strlen(Save->Text)+1;
it=(it>500000)?500000:it;
fwrite(&(Save->OnTime),sizeof(double),1,F);
fwrite(&(Save->OffTime),sizeof(double),1,F);
fwrite(&(Save->Check),sizeof(bool),1,F);
fwrite(&(Save->Tag),sizeof(int),1,F);
fwrite(&(Save->Mode),sizeof(char),1,F);
fwrite(&it,sizeof(int),1,F);
fwrite(Save->Text,sizeof(char),it,F);  
Save=Save->next;
tmp++;
}
while(Save);
fclose(F);
if(tmp==Counts)return tmp;
else return 0;
}
/******************************************************************************/
int Mess::LoadToFile(AnsiString f)
{
unsigned tmp=0;
double On,Off;
bool Ch;
int Ta; unsigned it=0;
unsigned char M;
char* T;
FILE* F;
if((F=fopen(f.c_str(),"rb"))==0) return 0;
fread(&tmp,sizeof(int),1,F);
unsigned tmpControl=tmp;
do
{
fread(&On,sizeof(double),1,F);
fread(&Off,sizeof(double),1,F);
fread(&Ch,sizeof(bool),1,F);
fread(&Ta,sizeof(int),1,F);
fread(&M,sizeof(char),1,F);
fread(&it,sizeof(int),1,F);
T = new char [it];
fread(T,sizeof(char),it,F);
Mess* tmpM=new Mess(On, Off, Ch, M, Ta, T);
delete []T;
tmp--;
}
while(tmp);
fclose(F);
if(tmpControl==Counts)return Counts;
return 0;
}


Отредактировано Vasily — 09/02/2005, 15:54
AVC
Отправлено: 09.02.2005, 15:05


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

On success fread returns the number of items (not bytes) actually read.
On end-of-file or error it returns a short count (possibly 0).

Вот и проверяйте после каждого fread а сколько итемсов считано.
Vasily
Отправлено: 09.02.2005, 16:01


Дежурный стрелочник

Группа: Участник
Сообщений: 31



Спасибо, но это не лучший вариант, так как ничего не даст. Проверяя итемсы я только найду неожиданный конец файла.
Оказывается ошибка появляется при попытке выделить память под строку, а так как в самом размере мусор, то память мне не дают. Решил выйти из положения таким образом:
Дважды записываю длину строки, после чего при чтении сравниваю два числа, вот и все.
А try catch, я толком не разобрался как после перехвата исключения закрыть поток, он то остался внутри try и catch его не видит.
AVC
Отправлено: 09.02.2005, 16:20


Ветеран

Группа: Модератор
Сообщений: 1583



Ну, батенька мой! (простите, невольно вырвалось) Вам нужна проверка непротиворечивости данных. Ни кто лучше вас не знает что и как может быть, а что нет. Прочли размер строки — засомневайтесь, возможен ли такой? И дальше только если правдоподобен.

Кстати, конструктор Mes копирует T в себя? А куда девается tmpM в LoadToFile? Обычно пишут LoadFromFile.
Vasily
Отправлено: 09.02.2005, 16:25


Дежурный стрелочник

Группа: Участник
Сообщений: 31



Виноват, возможно не так выразился при постановке вопроса.
Просто нужен способ защиты проги от испорченного файла,
потому что при загрузке битого файла она просто слетала, а хотелось, чтоб она просто это принимала к сведению и не переживала особенно из-зи этого.
А размер строки я и сам на перед не знаю, просто доходило до того, что
из испорченного файла прога достает число INT_MAX, а стороку такую выделить не может, вот и споткнется, и стоит плачет.
Да Т копирует в себя. А tmpM больше не нужен, потому что в конструкторе он подключается в список.
А по поводу LoadFromFile спасибо учту.

Отредактировано Vasily — 09/02/2005, 17:37
AVC
Отправлено: 09.02.2005, 16:43


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

Просто нужен способ защиты проги от испорченного файла

Кроме перекрестных проверок, учитывающих знания о внутренней структуре файла ни чего предложить нельзя.

QUOTE

А размер строки я и сам на перед не знаю,

Очевидно, что он должен быть не нулевой и не более числа байт от текущей позиции до конца файла.

QUOTE

чтоб она просто это принимала к сведению и не переживала особенно из-зи этого.

Оберните вызов LoadFromFile в try catch, наприер так
try {LoadFromFile(f); }
catch (Exception &xcp) {ShowMessage(xcp.Message);}
Vasily
Отправлено: 09.02.2005, 20:44


Дежурный стрелочник

Группа: Участник
Сообщений: 31



А как в ходе чтения файла определить сколько до его конца?
Хотя наверно разница SEEK_END и SEEK_CUR?
И как закрыть поток FILE* который остается внутри LoadFromFile()?

Нет не помогает результат всегда 1, потому что SEEK_END и SEEK_CUR это define, соответственно 2 и 1.

Отредактировано Vasily — 09/02/2005, 22:22
AVC
Отправлено: 10.02.2005, 09:41


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE
как в ходе чтения файла определить сколько до его конца?
Хотя наверно разница SEEK_END и SEEK_CUR?
Нет не помогает результат всегда 1, потому что SEEK_END и SEEK_CUR это define, соответственно 2 и 1

Вы сами и ответили на свой вопрос smile.gif
Можно использовать ftell и fseek. Например так (старый досовский метод)
FILE *finp = fopen...
fseek(fopen, 0L, SEEK_END);
long fsize = ftell(stream);
fseek(fopen, 0L, SEEK_SET);
Остаток файла fsize — ftell(finp);

QUOTE

как закрыть поток FILE* который остается внутри LoadFromFile()?

Либо там же при возбуждении исключения, либо обернуть в try catch все от fopen до fclose и закрывать в catch, либо там же блок try __finally, либо открывать файл вне LoadFromFile()
Лично мне нравится такой вариант
if((F=fopen(f.c_str(),"rb"))==NULL) return 0;
try { ... while(tmp); }
catch (...) { fclose(F); return 0; } игнорирование любой ошибки
или
__finally { fclose(F); } в этом случае ошибка будет поймана уровнем выше.

А еще можно расставить в файле контрольные точки. Например, самое простое,
текущая позиция файла при записи (результат ftell). Или контрольные суммы.

Отредактировано AVC — 10/02/2005, 10:01
Treumer
Отправлено: 10.02.2005, 15:21


Станционный диспетчер

Группа: Участник
Сообщений: 92



QUOTE (Vasily @ 09/02/2005, 17:27)
Виноват, возможно не так выразился при постановке вопроса.
Просто нужен способ защиты проги от испорченного файла,
потому что при загрузке битого файла она просто слетала, а хотелось, чтоб она просто это принимала к сведению и не переживала особенно из-зи этого.

Ну так надо считать какой-нибудь CRC этого файла и дописывать его в конец...
А при чтении сначала считать всесь файл как поток байтов, посчитать CRC и если все сошлось — читать уже данные по формату...

Вернуться в Вопросы программирования в C++Builder