Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как обработать исключения при чтении/записи, на дискету? 
:(
    Опции темы
ДЫМ
Дата 6.10.2004, 01:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 224
Регистрация: 6.1.2004

Репутация: нет
Всего: 8



Казалось бы, что может быть проще, но поди ж ты.
Проблема такова: я в цикле копирую файл через буфер, используя файловые потоки
(при работе с Handle такая же история).
Примерно так (в упрощенном варианте)
Код
procedure TForm1.Button1Click(Sender: TObject);
var Stream1,Stream2:TFileStream;
    CopyBuffer:PChar;
    BytesCopied:Integer;
begin
// Создаем потоки для файлов
Stream1:=TFileStream.Create('C:\Test.txt',fmOpenRead);
Stream2:=TFileStream.Create('A:\Test.txt',fmCreate);
Stream1.Seek(0,soFromBeginning);
Stream2.Seek(0, soFromEnd);
// выделяем память под буфер
CopyBuffer:=PChar(AllocMem(1024));

try
 // тут непосредственно копируем
 While Stream1.Position<>Stream1.Size do
   begin
    BytesCopied:=Stream1.Read(CopyBuffer^,1024);
    Stream2.Write(CopyBuffer^,BytesCopied);
   end;

// какое-нибудь сообщение в случае ошибки
except
 ShowMessage('Ошибка!');
end;

FreeMem(CopyBuffer);
Stream1.Free;
Stream2.Free;

А потом вот что:
1) файл, который копируется (C:\Test.txt) весит 1 Mb, на дискете свободно от силы 50 Kb,
эти 50 килобайт записываются и ВСЁ, никакого исключения не возникает, цикл завершается,
хотя должно быть что-то вроде "На диске не хватает места";
2) если в процессе копирования вынуть дискету (может и такое быть),
то вообще начинается какая-то вакханалия - выскакикавает диалог с заголовком
"Windows - Устройство не готово", жму <Отмена>, выскакивает точно такой же диалог, но
с заголовком "Project1:Project1.exe - Устройство не готово", а затем уж и вовсе в трее сообщение
"Ошибка отложенной записи ", но НИ ЛОКАЛЬНЫЙ НИ ГЛОБАЛЬНЫЙ обработчики в моем приложении
не срабатывают. (При чем здесь "отложенная запись", её же надо отдельно организовывать через API).

Почему в первом случае не возникает исключения?
Как во втором случае обработать возникшие
исключения непосредственно в приложении, хотя бы после системного обработчика, чтобы
вообще понять - успешно прошло копирование или нет?
(Кстати, система - WinXP)

PM MAIL WWW   Вверх
Dimich
Дата 6.10.2004, 08:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 247
Регистрация: 25.8.2004
Где: Брянск

Репутация: нет
Всего: 7



Вот так ошибка обрабатывается, если не хватает места при копировании например. А вот как обработать "изъятие дискеты" пока не додумался.... Будем искать.......
Код
 // тут непосредственно копируем
 While Stream1.Position<Stream1.Size do
  begin
   BytesCopied:=Stream1.Read(CopyBuffer^,1024);
   if Stream2.Write(CopyBuffer^,BytesCopied) <> BytesCopied then
     begin
       ShowMessage('Ошибка при копировании!');
       break;
     end;
  end;


--------------------
Не работает - исправь, работает - не трогай!!!
PM MAIL ICQ Jabber   Вверх
ДЫМ
Дата 7.10.2004, 01:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 224
Регистрация: 6.1.2004

Репутация: нет
Всего: 8



Но как отключить системный обработчик?
PM MAIL WWW   Вверх
Dimich
Дата 7.10.2004, 07:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 247
Регистрация: 25.8.2004
Где: Брянск

Репутация: нет
Всего: 7



Даже не знаю... не получается! Как то раньше не задумывался над этим, все время старался работать с файлами (когда это возможно) не через потоки, а по старинке через BlockRead/BlockWrite так такой бяки не возникает. Может это будет решением для твоей проблемы? Если у кого есть еще мысли, ответьте пожалуйста! Этот вопрос интерестен и мне...
--------------------
Не работает - исправь, работает - не трогай!!!
PM MAIL ICQ Jabber   Вверх
Girder
Дата 7.10.2004, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 25
Всего: 155



Цитата
Если у кого есть еще мысли, ответьте пожалуйста!
Данные потоки это не примочка Delphi - а надстройка. В частости для записи они используют API функцию WriteFile по этому надо указать системе(Windows) обработать ошибки самой или нет(И Delphi здесь не причем). Например API функция SetErrorMode и еже с ними smile.gif

К примеру код, для копирования, устраняет почти все проблеммы:
Код
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Edit1: TEdit;
   Edit2: TEdit;
   Button1: TButton;
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;        

var
 Form1: TForm1;

implementation

{$R *.dfm}

function Copy_File(const InFilePath,OutFilePath: String):Int64;
var InFP,OutFP:TFileStream;
   Size:Int64;
   ErrOld:Cardinal;
begin
Result:=0;
InFP:=nil;
OutFP:=nil;
try
 InFP:=TFileStream.Create(InFilePath,fmOpenRead);
except
 Result:=-1;
end;
if Result<0 then exit;
try
 OutFP:=TFileStream.Create(OutFilePath,fmCreate);
except
 Result:=-2;
end;
if Result<0 then
 begin
  InFP.Free;
  exit;
 end;
try
 Size:=InFP.Size;
 InFP.Seek(0,soFromBeginning);
except
 Size:=-3;
end;
ErrOld:=SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX);
if Size>=0 then
 begin
  try
   Result:=OutFP.CopyFrom(InFP,Size);
  except
   Result:=-4;
  end;
 end else Result:=-1;
SetErrorMode(ErrOld);
InFP.Free;
try
 OutFP.Free; //При ошибке - здесь все равно выдаст окно! так как попытается закрыть(CloseHandle) дескриптор файла!
except
end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var sIn,sOut:String;
begin
sIn:=trim(edit1.Text);
sOut:=trim(edit2.Text);
Caption:=IntToStr(Copy_File(sIn,sOut));
SetLastError(0);
end;

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

Удачи.

Это сообщение отредактировал(а) Girder - 7.10.2004, 15:38


--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
ДЫМ
Дата 8.10.2004, 01:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 224
Регистрация: 6.1.2004

Репутация: нет
Всего: 8



Функция SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX) никак не влияет на то, что появляется окно системного обработчика, если вынуть дискету во время копирования. Да и метод CopyFrom мне не подходит, очень надо через буфер
Глючная вещь - эти потоки
Цитата
try
OutFP.Free; //При ошибке - здесь все равно выдаст окно! так как попытается закрыть(CloseHandle) дескриптор файла!
except
end;


здесь надо бы добавить
Код

except
OutFP:=nil;
end;


Ну и шут с этими окошками, какой-никакой выход я нашел
Код

procedure TForm1.Button1Click(Sender: TObject);
var Stream1,Stream2:TFileStream;
 CopyBuffer:PChar;
 BytesCopied:Integer;
begin
// используем SetLastError
SetLastError(NO_ERROR);
// Создаем потоки для файлов
Stream1:=TFileStream.Create('C:\Test.txt',fmOpenRead);
Stream2:=TFileStream.Create('A:\Test.txt',fmCreate);
Stream1.Seek(0,soFromBeginning);
Stream2.Seek(0, soFromEnd);
// выделяем память под буфер
CopyBuffer:=PChar(AllocMem(1024));

try
// тут непосредственно копируем
While Stream1.Position<>Stream1.Size do
begin
 BytesCopied:=Stream1.Read(CopyBuffer^,1024);
 Stream2.Write(CopyBuffer^,BytesCopied);

 // проверяем на ошибку после файловых операций
 if GetLastError<>0 then
    Raise Exception.Create(SysErrorMessage(GetLastError));

end;

// какое-нибудь сообщение в случае ошибки
except
on OE:Exception do ShowMessage(OE.Message)
end;

// тут при желании тоже можно обработать
FreeMem(CopyBuffer);
Stream1.Free;
Stream2.Free;


Но все-таки можно ли не прибегая к API, подавить окошки системного обработчика?

PM MAIL WWW   Вверх
Girder
Дата 8.10.2004, 10:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 25
Всего: 155



Цитата
Функция SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX) никак не влияет на то, что появляется окно системного обработчика, если вынуть дискету во время копирования.
А ты убери из моего примера OutFP.Free и посмотри как он влияет в двух вариантах исполнения:
а)все остальное оставь как есть;
б)замени ErrOld:=SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX) на SetErrorMode(0) и удали SetErrorMode(ErrOld);

Это сообщение отредактировал(а) Girder - 8.10.2004, 10:09


--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
Girder
Дата 8.10.2004, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 25
Всего: 155



Переписал не много свой пример, не знаю у кого как, но у меня вообще не происходит вызова системного обработчика (но лудше конечно использовать API):
Код
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;        

var
  Form1: TForm1;

implementation

{$R *.dfm}

function Copy_File(const InFilePath,OutFilePath: String):Int64;
var InFP,OutFP:TFileStream;
    Size:Int64;
    ErrOld:Cardinal;
    P:PInteger;
begin
 Result:=0;
 InFP:=nil;
 OutFP:=nil;
 try
  InFP:=TFileStream.Create(InFilePath,fmOpenRead);
 except
  Result:=-1;
 end;
 if Result<0 then exit;
 try
  OutFP:=TFileStream.Create(OutFilePath,fmCreate);
 except
  Result:=-2;
 end;
 if Result<0 then
  begin
   InFP.Free;
   exit;
  end;
 try
  Size:=InFP.Size;
  InFP.Seek(0,soFromBeginning);
 except
  Size:=-3;
 end;
 ErrOld:=SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX);
 if Size>=0 then
  begin
   try
    Result:=OutFP.CopyFrom(InFP,Size);
   except
    begin
     p:[email protected];
     p^:=-1; 
     Result:=-4;
    end;
   end;
  end else Result:=-1;
 InFP.Free;
 try
  OutFP.Free;
 except
 end;
 SetErrorMode(ErrOld);
end;


procedure TForm1.Button1Click(Sender: TObject);
var sIn,sOut:String;
begin
 sIn:=trim(edit1.Text);
 sOut:=trim(edit2.Text);
 SetErrorMode(0);    
 Caption:=IntToStr(Copy_File(sIn,sOut));
 SetLastError(0);
end;

end.


Удачи.

Это сообщение отредактировал(а) Girder - 22.7.2005, 22:29


--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0971 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.