2017-04-26 19 views
5

tôi muốn triển khai sự kiện tiến độ trên TFileStream để biết thao tác đọc/ghi để chỉ định trên thanh tiến trình.Delphi: Tiến trình đọc/ghi TFileStream (không lãng phí hiệu năng)

Tôi có tạo ra một lớp clild (TProgressFileStream) của TFileStream:

unit ProgressFileStream; 

interface 

uses 
    System.SysUtils, 
    System.Classes; 

type 
    TProgressFileStreamOnProgress = procedure(Sender: TObject; Processed: Int64; Size: Int64; ContentLength : Int64; TimeStart : cardinal) of object; 
    TProgressFileStream = class(TFileStream) 
    private 
    FOnProgress: TProgressFileStreamOnProgress; 
    FProcessed:  Int64; 
    FContentLength: Int64; 
    FTimeStart:  cardinal; 
    FBytesDiff:  cardinal; 
    FSize:   Int64; 

    procedure Init; 
    procedure DoProgress(const AProcessed : Longint); 
    protected 
    procedure SetSize(NewSize: Longint); overload; override; 
    public 
    constructor Create(const AFileName: string; Mode: Word); overload; 
    constructor Create(const AFileName: string; Mode: Word; Rights: Cardinal); overload; 

    function Read(var Buffer; Count: Longint): Longint; overload; override; 
    function Write(const Buffer; Count: Longint): Longint; overload; override; 
    function Read(Buffer: TBytes; Offset, Count: Longint): Longint; overload; override; 
    function Write(const Buffer: TBytes; Offset, Count: Longint): Longint; overload; override; 
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; override; 

    property OnProgress: TProgressFileStreamOnProgress read FOnProgress write FOnProgress; 
    property ContentLength: Int64 read FContentLength write FContentLength; 
    property TimeStart: cardinal read FTimeStart write FTimeStart; 
    property BytesDiff: cardinal read FBytesDiff write FBytesDiff; 
    end; 

implementation 

uses 
    Winapi.Windows; 

{ TProgressFileStream } 

constructor TProgressFileStream.Create(const AFileName: string; Mode: Word); 
begin 
    inherited Create(AFileName, Mode); 

    Init; 
end; 

constructor TProgressFileStream.Create(const AFileName: string; Mode: Word; Rights: Cardinal); 
begin 
    inherited Create(AFileName, Mode, Rights); 

    Init; 
end; 

function TProgressFileStream.Read(var Buffer; Count: Longint): Longint; 
begin 
    Result := inherited Read(Buffer, Count); 

    DoProgress(Result); 
end; 

function TProgressFileStream.Write(const Buffer; Count: Longint): Longint; 
begin 
    Result := inherited Write(Buffer, Count); 

    DoProgress(Result); 
end; 

function TProgressFileStream.Read(Buffer: TBytes; Offset, Count: Longint): Longint; 
begin 
    Result := inherited Read(Buffer, Offset, Count); 

    DoProgress(Result); 
end; 

function TProgressFileStream.Write(const Buffer: TBytes; Offset, Count: Longint): Longint; 
begin 
    Result := inherited Write(Buffer, Offset, Count); 

    DoProgress(Result); 
end; 

function TProgressFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; 
begin 
    Result := inherited Seek(Offset, Origin); 

    if Origin <> soCurrent then 
    FProcessed := Result; 
end; 

procedure TProgressFileStream.SetSize(NewSize: Longint); 
begin 
    inherited SetSize(NewSize); 

    FSize := NewSize; 
end; 

procedure TProgressFileStream.Init; 
const 
    BYTES_DIFF = 1024*100; 
begin 
    FOnProgress := nil; 
    FProcessed  := 0; 
    FContentLength := 0; 
    FTimeStart  := GetTickCount; 
    FBytesDiff  := BYTES_DIFF; 
    FSize   := Size; 
end; 

procedure TProgressFileStream.DoProgress(const AProcessed : Longint); 
var 
    aCurrentProcessed : Longint; 
begin 
    if not(Assigned(FOnProgress)) then Exit; 

    aCurrentProcessed := FProcessed; 

    Inc(FProcessed, AProcessed); 

    if FContentLength = 0 then 
    FContentLength := FSize; 

    if (FProcessed = FSize) or (FBytesDiff = 0) or (aCurrentProcessed - FBytesDiff < FProcessed) then 
    FOnProgress(Self, FProcessed, FSize, FContentLength, FTimeStart); 
end; 

end. 

Một sử dụng cơ bản là

procedure TWinMain.ProgressFileStreamOnProgressUpload(Sender: TObject; Processed: Int64; Size: Int64; ContentLength : Int64; TimeStart : cardinal); 
begin 
    if Processed > 0 then 
     ProgressBar.Position := Ceil((Processed/ContentLength)*100); 
end; 

procedure TWinMain.BtnTestClick(Sender: TObject); 
const 
    ChunkSize = $F000; 
var 
    aBytes:  TBytes; 
    aBytesRead : integer; 
    aProgressFileStream : TProgressFileStream; 
begin 
    aProgressFileStream := TProgressFileStream.Create('MyFile.zip', fmOpenRead or fmShareDenyWrite); 
    SetLength(aBytes, ChunkSize); 
    try 
    aProgressFileStream.OnProgress := ProgressFileStreamOnProgressUpload; 

    aProgressFileStream.Seek(0, soFromBeginning); 
    repeat 
     aBytesRead := aProgressFileStream.Read(aBytes, ChunkSize); 
    until (aBytesRead = 0); 

    finally 
    aProgressFileStream.Free; 
    end; 
end; 

vấn đề là trong phương pháp làm gọi sự kiện này, tôi muốn gọi sự kiện này mỗi FBytesDiff (từ mặc định mỗi 100 KByte):

procedure TProgressFileStream.DoProgress(const AProcessed : Longint); 
var 
    aCurrentProcessed : Longint; 
begin 
    if not(Assigned(FOnProgress)) then Exit; 

    aCurrentProcessed := FProcessed; 

    Inc(FProcessed, AProcessed); 

    if FContentLength = 0 then 
    FContentLength := Size; 

    if (FProcessed = Size) or (FBytesDiff = 0) or (FProcessed - aCurrentProcessed > FBytesDiff) then 
    FOnProgress(Self, FProcessed, Size, FContentLength, FTimeStart); 
end; 

nhưng sự kiện dường như được kích hoạt trên mỗi ChunkSize (61440 byte - 60 KB) ...

Tôi muốn thêm điều khiển này để không lãng phí hiệu suất đọc/ghi luồng với quá nhiều sự kiện gọi.

+1

Ý tưởng hay và hữu ích, như –

Trả lời

5

Đã xử lý - aCurrentProcessed sẽ trả về kích thước Chunk. Tôi nghĩ bạn nên tạo một biến để lưu trữ khối đọc FReadSize, khởi tạo nó bằng 0. Tăng biến đó với byte đã đọc, nếu kích thước đọc lớn hơn FBytesDiff trừ FBytesDiff khỏi FReadSize.

procedure TProgressFileStream.DoProgress(const AProcessed : Longint); 
var 
    aCurrentProcessed : Longint; 
begin 
    if not(Assigned(FOnProgress)) then Exit; 

    aCurrentProcessed := FProcessed; 

    Inc(FProcessed, AProcessed); 
    Inc(FReadSize, AProcessed); 

    if FContentLength = 0 then 
    FContentLength := Size; 

    if (FProcessed = Size) or (FBytesDiff = 0) or (FReadSize >= FBytesDiff) then 
    begin 
    FOnProgress(Self, FProcessed, Size, FContentLength, FTimeStart); 
    FReadSize := FReadSize - FBytesDiff; 
    end; 
end; 
Các vấn đề liên quan