I want to copy many files in one, but using multiThread,supposing that file A is the file in which different threads copy datas, in this case each thread is meant to copy one fi
If you want to concatenate multiple input files in parallel into a single destination file, you can do it this way:
pre-allocate the destination file. Create the file, seek to the intended final concatenated file size, and set EOF to allocate the file on the file system. With a TFileStream
, this can be accomplished by simply setting the TFileStream.Size
property to the intended size. Otherwise, using the Win32 API directly, you would have to use CreateFile()
, SetFilePointer()
, and SetEndOfFile()
.
Divide up the destination file into logical sections, each with a starting and ending offset within the file, and assign those sections to your threads as needed. Have each thread open its own local handle to the same destination file. That will allow each thread to seek and write independently. Make sure each thread does not leave its assigned section so it does not corrupt another thread's written data.
For example:
type
TFileInfo = record
InFileName: String;
OutFileName: String;
OutFileStart: Int64;
OutFileSize: Int64;
end;
TCopyThread = class(TThread)
protected
FFileInfo: TFileInfo;
procedure Execute;
public
constructor Create(const AFileInfo: TFileInfo);
end;
constructor TCopyThread.Create(const AFileInfo: TFileInfo);
begin
inherited Create(False);
FFileInfo := AFileInfo;
end;
procedure TCopyThread.Execute;
var
InStream: TFileStream;
OutStream: TFileStream;
begin
InStream := TFileStream.Create(FFileInfo.InFileName, fmOpenRead or fmShareDenyWrite);
try
OutStream := TFileStream.Create(FFileInfo.OutFileName, fmOpenWrite or fmShareDenyNone);
try
OutStream.Position := FFileInfo.OutFileStart;
OutStream.CopyFrom(InStream, FFileInfo.OutFileSize);
finally
OutStream.Free;
end;
finally
InStream.Free;
end;
end;
procedure ConcatenateFiles(const InFileNames: array of string; const OutFileName: string);
var
i: Integer;
OutStream: TFileStream;
FileInfo: array of TFileInfo;
TotalSize: Int64;
sr: TSearchRec;
Threads: array of TCopyThread;
ThreadHandles: array of THandle;
NumThreads: Integer;
begin
SetLength(FileInfo, Length(InFileNames));
NumThreads := 0;
TotalSize := 0;
for i := 0 to High(InFileNames) do
begin
if FindFirst(InFileNames[i], faAnyFile, sr) <> 0 then
raise Exception.CreateFmt('Cannot retrieve size of file: %s', [InFileNames[i]]);
if sr.Size > 0 then
begin
FileInfo[NumThreads].InFileName := InFileNames[i];
FileInfo[NumThreads].OutFileName := OutFileName;
FileInfo[NumThreads].OutFileStart := TotalSize;
FileInfo[NumThreads].OutFileSize := sr.Size;
Inc(NumThreads);
Inc(TotalSize, sr.Size);
end;
FindClose(sr);
end;
OutStream := TFileStream.Create(OutFileName, fmCreate);
try
OutStream.Size := TotalSize;
finally
OutStream.Free;
end;
SetLength(Threads, NumThreads);
SetLength(ThreadHandles, NumThreads);
for i := 0 to NumThreads-1 do
begin
Threads[i] := TCopyThread.Create(FileInfo[i]);
ThreadHandles[i] := Threads[i].Handle;
end;
i := 0;
while i < NumThreads do
begin
WaitForMultipleObjects(Min(NumThreads-i, MAXIMUM_WAIT_OBJECTS), ThreadHandles[i], TRUE, INFINITE);
Inc(i, MAXIMUM_WAIT_OBJECTS);
end;
for i := 0 to NumThreads-1 do
begin
Threads[i].Terminate;
Threads[i].WaitFor;
Threads[i].Free;
end;
end;