![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Для опытного глаза
Dennis I. Komarov © (2007-10-16 10:11:00)код модуля потока предназначенного для транспорта пакетов с диска в и-нет(FTP)
Еще неизвестно как будет хранится база клиентов и не ведуться логи
Просьба посмотреть данный код на корректность, в смысле поведения при нестабильном конекте (ну и вообще :) )
unit u_send;
interface
uses
Classes, Windows, SysUtils, StrUtils, DateUtils,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdFTP, IniFiles;
type
TThreadSend = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
var
FTP: TIdFTP;
implementation
uses
Main;
{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TThreadSend.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }
{ TThreadSend }
procedure TThreadSend.Execute;
var
SearchRec: TSearchRec;
FindResult: Integer;
ClientCode: string;
FTPLogin: string;
HomeDir: string;
begin
{ Place thread code here }
FTP:=TIdFTP.Create(nil);
try
FTP.Host:='**.**.**.***';
FTP.Username:='********';
FTP.Password:='********';
FTP.Passive:=true;
while not Terminated do begin
{для каждого клиента делать } begin
FindResult := FindFirst(BCDir + '\MAILBOX\' + ClientCode + '\POSTIN\*.*', faAnyFile, SearchRec);
while FindResult = 0 do begin
with SearchRec do
begin
if (Name <> '.') and (Name <> '..') then
if not (Attr and faDirectory <> 0)
then begin
if not(FTP.Connected) then
try
FTP.Connect;
HomeDir:=FTP.RetrieveCurrentDir;
except
FTP.Disconnect;
end;
if FTP.Connected then
try
FTP.ChangeDir(HomeDir + '/' + FTPLogin + '/MBOX/RT');
FTP.Put(BCDir + '\MAILBOX\' + ClientCode + '\POSTIN\' + Name, Name);
if FTP.Size(Name) = Size then begin
FTP.Rename(Name, '../R/' + Name);
DeleteFile(BCDir + '\MAILBOX\' + ClientCode + '\POSTIN\' + Name);
end;
except
FTP.Disconnect;
end;
end;
FindResult:= FindNext(SearchRec);
end;
end;
FindClose(SearchRec);
end;
FTP.Disconnect;
Sleep(15000);
end;
finally
FTP.Disconnect;
FTP.Free;
end;
end;
end.
Dennis I. Komarov (2007-10-30 16:47:00) [21]Почему
> lpNumberOfBytesTansferred^
?
GetOverLappedResult(hDir, lpOverlapped^, lpNumberOfBytesTansferred, true)
третьим параметром указатель кушать не хочет, хотя в справке LPDWORD
В функции хочет Cardinal а на Pointer ругается.
> От балды ты поставил, а не "из-за щедрости")
Неее, балда подумала, что этого более чем хватит!
A array [0..4095] of ... почему низя сделать? Получим такойже объем (64*1024 = SizeOf(TFileNotifyInformation)*4096). По идее все должно оказаться в массиве. С ним же удобнее работать. Ну и пусть памяти быдет выделено немного больше (65Kb Не так страшно)
Сергей М. (2007-10-30 16:11:00) [22]
> Дабы если false, то пытался поставить запрос заново
Малацца, что тут сказать)
А почему false - тебе по барабану.
Жди бесконечного цикла)
> А 1000 поставил из-за щедрости
От балды ты поставил, а не "из-за щедрости")
Программа, реализованная от балды, работать как положено никогда не будет.
У тебя есть lpNumberOfBytesTansferred^, у тебя есть связный список в lpBuf^, вот пробегись по этому списку и выдели памяти под врем.буфер ровно столько, сколько нужно, но не более lpNumberOfBytesTansferred^
Dennis I. Komarov (2007-10-30 15:50:00) [23]> Накой ляд тут этот цикл ?
Дабы если false, то пытался поставить запрос заново :)
> Как кореллирует sizeof(TTFileNotifyInformationArray) c 64*1024
> и lpNumberOfBytesTansferred^ ?
Откровенно говоря никак, но он веди не меньше получится. Я так понимаю, что остальные элементы массива просто пустыми остануться. А 1000 поставил из-за щедрости :)
Ок, понял. Меняем packed record на просто record
array [0..4095] of ....
Сергей М. (2007-10-30 15:33:00) [24]Действительно безобразие)
> while not ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf),
> true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped,
> nil) do;
Накой ляд тут этот цикл ?
> tBuf:=TTFileNotifyInformationArray(lpBuf^);
А это что такое ?
Как кореллирует sizeof(TTFileNotifyInformationArray) c 64*1024 и lpNumberOfBytesTansferred^ ?
Dennis I. Komarov (2007-10-30 15:23:00) [25]
unit u_send;
interface
uses
Classes, Windows, SysUtils, StrUtils, DateUtils,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdFTP, IniFiles;
type
TThreadSend = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
implementation
uses
Main;
{ TThreadSend }
type
PFileNotifyInformation = ^TFileNotifyInformation;
TFileNotifyInformation = packed record
NextEntryOffset: DWORD;
Action: DWORD;
FileNameLength:DWORD;
FileName: WideChar;
end;
TTFileNotifyInformationArray = array[0..1000] of TFileNotifyInformation;
procedure TThreadSend.Execute;
var
i: Integer;
tBuf: TTFileNotifyInformationArray;
hDir, hDirChangeEvent: THandle;
lpBuf: Pointer;
lpOverlapped: POverlapped;
lpNumberOfBytesTansferred: Cardinal;
begin
{ Place thread code here }
FreeOnTerminate:=false;
hDirChangeEvent:=CreateEvent(nil, false, false, PChar('OnChangeDirecory'));
hDir := CreateFile ( 'c:\test', GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
if hDir <> INVALID_HANDLE_VALUE then begin
GetMem(lpBuf, 64*1024);
GetMem(lpOverlapped, SizeOf(lpOverlapped^));
try
ZeroMemory(lpBuf, 64*1024);
lpOverlapped^.hEvent:=hDirChangeEvent;
if ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil) then
while not Terminated do begin
if (WaitForSingleObject(hDirChangeEvent, 1000) = WAIT_OBJECT_0) and
(GetOverLappedResult(hDir, lpOverlapped^, lpNumberOfBytesTansferred, true)) then begin
//Копируем результаты в резервный буфер
tBuf:=TTFileNotifyInformationArray(lpBuf^);
while not ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil) do;
i:=0;
repeat
{
Разбераем tBuf[i]
Если появился новый => шмаляем, исли гуд то в архив
{}
Inc(i);
until tBuf[i].NextEntryOffset > 0
end;
end;
finally
FreeMem(lpBuf);
FreeMem(lpOverlapped);
CloseHandle(hDirChangeEvent);
CloseHandle(hDir);
end;
end;
end;
end.
Вот такой "безобразие". Как оно?
Сергей М. (2007-10-30 08:18:00) [26]
> Как быть?
Ну как ?...
Конечно же скопировать содержимое lpBuf^ во временный буфер и разбирать уже этот временнный буфер, а не lpBuf^. Неужели это не очевидно ?
Dennis I. Komarov (2007-10-29 17:10:00) [27]> [47] Сергей М. © (26.10.07 16:51)
> if WaitFor...... and GetOverlappedResult(..) then
> begin
> if ReadDir...
> //далее разбираем lpBuf
Если получаем информацию, о появлении нового файла, то отправляем на FTP, исли он отправился успешно, то удаляем его => получаем очередное изменение, а значит lpBuf изменен, т.е. все остальные информацонные записи - утеряны :(
Как быть?
> end;
Сергей М. (2007-10-29 13:59:00) [28]
> как положено разбирать lpBuf?
В точном соответствии с офиц.описанием структуры FILE_NOTIFY_INFORMATION.
> Ведь там может храниться несколько записей типа
И что ?
Dennis I. Komarov (2007-10-29 13:52:00) [29]А как положеноразбирать lpBuf? Ведь там может храниться несколько записей типа TFileNotifyInformation.
Сергей М. (2007-10-26 16:51:00) [30]if WaitFor...... and GetOverlappedResult(..)then
begin
if ReadDir...
//далее разбираем lpBuf
end;
Dennis I. Komarov (2007-10-26 16:35:00) [31]Как понимаю, lpBuff заполняется пакетамя типа TFileNotifyInformation, в котором NextEntryOffset отвечает за существование следующего пакета. Отсюда и возник вопрос, нужен ли pNumberOfBytesTranferred вообще.
И как лучше сделать:
1.
...
if WaitFor...... do
begin
if ReadDir...
//далее разбираем lpBuf
end;
2.
if WaitFor...... do
begin
//тут разбираем lpBuf
if ReadDir...
end;
Сергей М. (2007-10-26 15:51:00) [32]
> Dennis I. Komarov © (26.10.07 15:47) [44]
А, ты вон про что ..
Ну да, в дельфийской декларации этот параметр объявлен для передачи по ссылке, т.е. как var-параметр.
> Мой скромный перевод - это скока надо читать ин-фы из lpBuf.
> (разумеется не переменная)
Правильно перевел.
Dennis I. Komarov (2007-10-26 15:47:00) [33]> Это Points to a 32-bit variable that receives the number
> of bytes that were actually transferred by a read or write
> operation
Я F1 умею жать :) только не понял почему Point s
Мой скромный перевод - это скока надо читать ин-фы из lpBuf. (разумеется не переменная)
Сергей М. (2007-10-26 14:40:00) [34]
> Ибо обновление по F5 получаем
А у меня Explorer самотслеживает изменения в показываемой им в тек.момент директории.
Что я делаю не так ?
> А первоначальную информацию он как читает?
А по барабану как он ее читает. Мы же об отслеживании изменений речь ведем)
> это VAR ?
Это Points to a 32-bit variable that receives the number of bytes that were actually transferred by a read or write operation
> Он вообще имеет значение
А нафига он тогда фигурирует в структуре, если он якобы не нужен ?
Dennis I. Komarov (2007-10-26 13:34:00) [35]> С чего ты так уверен ?
Ибо обновление по F5 получаем. Я сомниваюсь, что все это время Explorer хранит эти изменения, и отображает их по команде.
А первоначальную информацию он как читает?
----------
lpNumberOfBytesTranferred - это VAR ? Он вообще имеет значение, ведь читаль lpBuf будем.
Сергей М. (2007-10-26 12:32:00) [36]
> Dennis I. Komarov © (26.10.07 12:26) [40]
> Но ведь не асинхронный.
С чего ты так уверен ?
Да и какая разница, синхронный или асинхронный ?
Режим не имеет значения с т.з. твоих волнений насчет "потерь" .
Dennis I. Komarov (2007-10-26 12:26:00) [37]> [39] Сергей М. © (26.10.07 11:44)
Но ведь не асинхронный.
Сергей М. (2007-10-26 11:44:00) [38]
> "сканить" диск всетаки надежнее
С чего бы ?
Explorer, заметь, использует именно ReadDirectoryChangesW
Сергей М. (2007-10-26 11:23:00) [39]
> чего она сюда хочет?
hDir твой она хочет.
Dennis I. Komarov (2007-10-26 09:57:00) [40]> Нет. Поэтому следует как можно быстрей после сигнала ивента
> принять решение о постановке очередного запроса и лишь потом
> разбирать результаты текущего выполненного.
Гм... Но для этого все равно понадобится какое то время, т.е.
Получили сигнал события, далее по идее запроса в очереди нет, следует отправить его еще раз, отправлять с тем же указателем на буфер низя - можем потерять его, следовательно, предварительно надо сохранить данные, это потребует некоторого времени, за которое могут произойти изменения, начинаю подумывать о том, что "сканить" диск всетаки надежнее
> Мало ли что могло произойти во время исполнения запроса
> !
> Ф-ция как раз и покажет, успешно ли выполнен запрос.
> А сигнал ивента лишь фиксирует факт завершения (успешного
> или неуспешного) асинхронной операции.
hFile - чего она сюда хочет?