![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TThread копирование файла в 2-х потоках [D7]
PacMan © (2012-05-01 20:31:00)Помогите кто-нибудь.
Нужно в 2-х потоках копировать файл.
1-й поток читает файл и пишет данные в буфер1, затем содержимое буфера 1 передает в буфер 2.
2-й поток пишет из буфера 2 в файл.
бьюсь уже давно, ни как не могу понять как работают потоки.. как 1 заставить ждать, пока не выполнится что-либо во-2м...
листинг:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, unit2, StdCtrls, SyncObjs, Gauges;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
Label3: TLabel;
Gauge1: TGauge;
procedure Button1Click(Sender: TObject);
procedure Edit1Click(Sender: TObject);
procedure Edit2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
CriticalSection:=TCriticalSection.Create;
stream1.Create(false);
stream2.Create(false);
end;
procedure TForm1.Edit1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
Edit1.Text := OpenDialog1.FileName;
end;
procedure TForm1.Edit2Click(Sender: TObject);
begin
if SaveDialog1.Execute then
Edit2.Text := SaveDialog1.FileName;
end;
end.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SyncObjs;
type
stream1 = class(TThread)
protected
public
Procedure Podgot;
Procedure ZabivBuf;
Procedure Zakon;
procedure Execute; override;
end;
stream2 = class(TThread)
protected
public
procedure Execute; override;
procedure FWrite;
end;
var
f1, f2: File; // первый и второй файл
buf1: array [1..8192] of Char; //буфер 1
buf2: array [1..8192] of Char; //буфер 2
sizefile, sizeread: Int64; //размер файла и размер прочитанного
colRead, colWrite : Integer; //прочитано и записано
fOtkuda, fKuda : String; //адреса и имена файлов
CriticalSection: TCriticalSection;
flag: Boolean;
implementation
uses unit1;
procedure stream1.Execute;
begin
Podgot;
while colRead = colWrite do
begin
if flag=false then //если буфер 2 уже пустой
begin
CriticalSection.Enter;
ZabivBuf;
end;
end;
Zakon;
end;
procedure stream2.Execute;
begin
while colRead = colWrite do
begin
if flag=True then //если буфер 2 уже пустой
begin
CriticalSection.Enter;
Fwrite;
end;
end;
end;
Procedure stream1.Podgot; // подготовка
var i:integer;
begin
{i-} //даем компилятору директиву, чтобы не отслеживал ошибки ввода-вывода:
if (Form1.Edit1.Text='') or (Form1.Edit2.Text='') then //проверяем, указаны ли файлы. если нет - выходим
begin
ShowMessage('Вы не указали данные для копирования');
Exit;
end;
//Try
AssignFile(f1, Form1.Edit1.Text); //связываем файловые переменные:
AssignFile(f2, Form1.Edit2.Text);
Reset(F1, 1); //связываем файловые переменные:
sizefile := FileSize(f1); //определяем его размер в переменную:
Form1.Label3.Caption := 'Размер файла: '+IntToStr(Round(sizefile / 8192)) + ' Кб.'; //отображаем размер файла в килобайтах:
Rewrite(f2, 1); //создаем или перезаписываем второй файл:
colRead := 0; //делаем, пока не достигнут конец исходного файла
colWrite := 0;
sizeread := 0;
Screen.Cursor := crHourGlass; //песочные часы
{i+}
end;
Procedure Stream1.ZabivBuf;
var
i:integer; //while colRead = colWrite do
begin
{i-}
BlockRead(f1, Buf1, SizeOf(Buf1), colRead);
//if colRead = 0 then break;
for I := 1 to 8192 do
Buf2[i]:=Buf1[i]; //Буфер1 в Буфер2
Form1.Gauge1.Progress := Round(100*sizeread/sizefile);
Flag:=True;
CriticalSection.Leave;
{i+}
end;
Procedure Stream1.Zakon;
begin
{i-}
Screen.Cursor := crDefault; //обычный вид курсора
//Finally
CloseFile(f1);
CloseFile(f2);
//end; //try
fOtkuda := Form1.Edit1.Text; //исправляем дату
fKuda := Form1.Edit2.Text;
if IOResult <> 0 then
Application.MessageBox('Ошибка при копировании файла!', 'Внимание!!!',
MB_OK+MB_ICONERROR)
else ShowMessage('Копирование завершено успешно');
//включаем обработчик компилятором ошибок
{i+}
End;
procedure stream2.FWrite;
var
i: Integer;
begin
BlockWrite(f2, Buf2, colRead, colWrite);
sizeread := sizeread + colRead;
Flag:=False;
CriticalSection.Leave;
end;
end.
Германн (2012-05-03 01:54:00) [21]
> Sha © (03.05.12 01:20) [22]
Ностальгия?
Sha (2012-05-03 01:20:00) [22]> PacMan ©
Почитай про кольцевой буфер клавиатуры,
прерывания 9 и 16, можно поверхностно.
Изобрази ей нечто похожее.
Сергей М. (2012-05-02 22:43:00) [23]
> Anatoly Podgoretsky © (02.05.12 21:36) [20]
А может просто не сделал, притом что должен был сделать ?
imho, сей вариант наиболее вероятен)
Anatoly Podgoretsky (2012-05-02 21:36:00) [24]> PacMan (02.05.2012 19:41:17) [17]
А что ты ей плохого сделал?
Андреевич (2012-05-02 21:13:00) [25]
> там на самом деле гинеальная идея заложена :)
> типа пока один поток пишет первый кусок,другой читает второй
> и тд
> но она имеет смысл только при наличии 2х жестких дисков
> , если источник на одном а приемник на другом
или если источники типа \\server\share\file.txt
Сергей М. (2012-05-02 20:44:00) [26]
> сам а
Это многое что объясняет)
PacMan (2012-05-02 19:41:00) [27]
> Sha © (02.05.12 12:57) [15]
Это текст задания слово в слово.
Причем сама препод не может ни чего пояснить по нему.
Спрашиваю из элементов какого типа состоят массивы(массив байт или строки или еще что)? Отвечает, что как мне удобнее пусть так и будет, а про копирование вообще ни чего сказать не может.
как-то так.
Anatoly Podgoretsky (2012-05-02 13:43:00) [28]> Sha (02.05.2012 12:57:15) [15]
Это тест на испытание копипастеров, не выживет так не выживет.
Sha (2012-05-02 12:57:00) [29]> PacMan © (02.05.12 10:24) [10]
> при помощи тройной буферизации.
обычно говорят буферизации чего, какой операции
> Программа должна использовать потоки
ну раз надо, значит, надо
> Буферизацию реализовать из 2-х массивов, состоящих из 3-х элементов.
всего 3 или 3 в каждом массиве? элементы - это что? обычно указатели
> Первый массив отвечает за чтение из файла, а второй за запись.
переменная ни за что никому не отвечает
> Первый поток получает имя файла,
> берет пустой элемент из первого массива,
> записывает в него блок данных..
значит, элемент - не указатель?
> и передает второму массиву этот блок данных.
передать переменной? она же памятник
копирование данных или указателей?
кто об этом и как узнает?
а если некуда передавать? табличка "занято" 3 раза?
> При этом буфер, в котором считали блок данных, обнуляется.
нафига? если в нем были данные - то это бред
может, указатель, хотя это тоже не оптимал
> Второй поток, видя, что во втором массиве есть полный буфер,
просто песня! КАК он это видит?
> записывает этот буфер в файл и обнуляет его.
опять же нафига?
опять же, если видит, но не может? типа еще е все доделал
> При этом, в первом массиве выделяется новый буфер.
вроде мы не удаляли ничего,
в таком случае лимит в 3 буфера будет превышен!
> Cobalt
Конечно, можно мониторить поступление телефонного звонка,
но, вероятно, намного проще брать трубку по звонку.
Cobalt (2012-05-02 11:54:00) [30]Имитация обработки - один поток откуда-то получает данные, складирует их в буфер.
Второй поток - мониторит поступлени данных, и записывает их в файл, например, в базу данных.
Вполне жизненная ситуация.
PacMan (2012-05-02 11:52:00) [31]ага)
это сфотографировано лично)
Sha (2012-05-02 11:36:00) [32]> PacMan © (02.05.12 10:24) [10]
Формулировка ужасная. Это точно оригинальный текст "от препода"?
PacMan (2012-05-02 10:30:00) [33]Есть коммерческое предложение, т.к. сам это все равно не напишу.
Если кто желает заморочиться по заданию, договоримся о цене.
Кто надумает, пишите в мыло yrungxay@mail.ru
PacMan (2012-05-02 10:24:00) [34]
> Это ты сам придумал или препод навязал тебе именно такую
> логику ?
на самом деле задание звучит так:
"Разработать компонент, реализующий копирование файлов, при помощи тройной буферизации. Программа должна использовать потоки. Первый поток считывает блок данных из указанного файла. Второй поток записывает этот блок данных в файл. Буферизацию реализовать из 2-х массивов, состоящих из 3-х элементов. Каждый элемент - это буфер. Первый массив отвечает за чтение из файла, а второй за запись. Первый поток получает имя файла, берет пустой элемент из первого массива, записывает в него блок данных и передает второму массиву этот блок данных. При этом буфер, в котором считали блок данных, обнуляется. Второй поток, видя, что во втором массиве есть полный буфер, записывает этот буфер в файл и обнуляет его. При этом, в первом массиве выделяется новый буфер. И так пока весь файл не будет скопирован"
!НО! я даже малейшего представления не имею как это реализовать. Вот и решил упростить "слегка".
если у кого-нибудь есть идеи как это сделать, или еще лучше исходники... буду просто счастлив))
надеюсь не сильно запутал.
Sha (2012-05-02 02:08:00) [35]http://www.delphimaster.net/view/2-1202729073
sniknik (2012-05-01 23:05:00) [36]кстати в цикле второго потока (или вообще) ошибка... он не завершается. исправь.
sniknik (2012-05-01 22:50:00) [37]оптимальностью не пахнет, сама логика кривая, но... более... не знаю даже как сказать, но работоспособно это точно. -
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Gauges, StdCtrls;
const
WM_WRITE = WM_USER + 101;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Gauge1: TGauge;
procedure Button1Click(Sender: TObject);
private
procedure WMWrite(var Msg: TMessage); message WM_WRITE;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
BufSize = 4096;
WM_BUF = WM_USER + 102;
type
TFileRead = class(TThread)
protected
F: File;
FName: string;
ThreadID2: integer;
procedure Execute; override;
public
constructor Create(ID2: integer; const Name: string);
end;
TFileWrite = class(TThread)
protected
F: File;
FName: string;
MainHandle: THandle;
procedure Execute; override;
public
constructor Create(Handle: THandle; const Name: string);
end;
constructor TFileRead.Create(ID2: integer; const Name: string);
begin
ThreadID2:= ID2;
FName := Name;
inherited Create(false);
end;
procedure TFileRead.Execute;
var
Buf: PChar;
NumRead: integer;
begin
AssignFile(F, FName);
Reset(F, 1);
repeat
GetMem(Buf, BufSize);
BlockRead(F, Buf^, BufSize, NumRead);
PostThreadMessage(ThreadID2, WM_BUF, integer(Buf), NumRead);
until (NumRead = 0);
CloseFile(F);
end;
constructor TFileWrite.Create(Handle: THandle; const Name: string);
begin
MainHandle:= Handle;
FName := Name;
inherited Create(false);
end;
procedure TFileWrite.Execute;
var
Buf: PChar;
NumWritten, Count: integer;
Msg: TMsg;
begin
AssignFile(F, FName);
Rewrite(F, 1);
Count:= 0;
while GetMessage(Msg, 0, 0, 0) do begin
DispatchMessage(Msg);
Buf := Pointer(Msg.wParam);
Count:= Count + Msg.lParam;
BlockWrite(F, Buf^, Msg.lParam, NumWritten);
FreeMem(Buf);
PostMessage(MainHandle, WM_WRITE, Count, 0);
end;
CloseFile(F);
end;
procedure TForm1.WMWrite(var Msg: TMessage);
begin
Gauge1.Progress:= Msg.WParam;
Button1.Enabled:= Gauge1.Progress = Gauge1.MaxValue;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
FileWrite: TFileWrite;
begin
with TFileStream.Create(Edit1.Text, fmOpenRead) do
try
Gauge1.MaxValue:= Size;
finally
Free;
end;
Button1.Enabled:= false;
FileWrite:= TFileWrite.Create(Handle, Edit2.Text);
TFileRead.Create(FileWrite.ThreadID, Edit1.Text);
end;
end.
Сергей М. (2012-05-01 22:18:00) [38]
> 1-й поток читает файл и пишет данные в буфер1, затем содержимое
> буфера 1 передает в буфер 2.
> 2-й поток пишет из буфера 2 в файл.
Это ты сам придумал или препод навязал тебе именно такую логику ?
QAZ (2012-05-01 22:16:00) [39]
> sniknik © (01.05.12 20:44) [1]
там на самом деле гинеальная идея заложена :)
типа пока один поток пишет первый кусок,другой читает второй и тд
но она имеет смысл только при наличии 2х жестких дисков , если источник на одном а приемник на другом
PacMan (2012-05-01 21:36:00) [40]ну синхронайз пока не трогаю... программа запускается и так.
при запуске я выбираю исходный файл, выбираю куда и под каким именем его скопировать...
по кнопке "что-то происходит" и в конце выводится "копирование успешно завершено".
открываю директорию назначения и вижу файлик с нужным именем... !НО! его размер 0 байт.
смотрел пошаговое выполнение, у меня запускается 1-й поток, проходит круг... ииииии..... "копирование завершено".
чтобы было понятнее что и как, могу на почту скинуть прогу.