Vasily |
Отправлено: 09.02.2005, 12:18 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 31
|
Подскажите как защитить чтение из файла.
Задача следующая:
Динамический массив char* необходимо положить в файл.
Реализация:
Вначале в файл кладу кол-во элементов массива,
затем сами char* (соответственно значения, а не адреса)
При чтении все нормально работает.
Но если файл поврежден, то соответственно все рушится.
Вопрос:
Как защитить чтение из файла, чтобы просто прерывалось чтение с сообщением о повреждении файла с возможностью продолжать выполнение программы.
|
|
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
|
Вы сами и ответили на свой вопрос
Можно использовать 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 и если все сошлось — читать уже данные по формату... |
|
|