how to make a multithread copy files

后端 未结 3 468
刺人心
刺人心 2021-01-27 16:37

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

3条回答
  •  情歌与酒
    2021-01-27 17:07

    If you want to concatenate multiple input files in parallel into a single destination file, you can do it this way:

    1. 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().

    2. 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;
    

提交回复
热议问题