首先,假設TStream
是瓶頸。您需要分析您的代碼,例如AQTime,以確定瓶頸的真正位置。不要做出假設。
其次,你實際使用什麼類型的TStream
? TMemoryStream
? TFileStream
?還有別的嗎?不同的流類型處理內存的方式不同TMemoryStream分配一個內存緩衝區,並在緩衝區填滿時按預設的字節數增長。另一方面,TFileStream
根本不使用任何內存,它只是直接寫入文件並讓操作系統處理任何緩衝。
無論您使用哪種類型的流,您可以嘗試的一件事是實現您自己的定製TStream
類,該類具有內部固定大小緩衝區和指向您的真實目標TStream
對象的指針。然後,您可以將您的自定義類的實例傳遞給您的算法。讓你的班級覆蓋TStream::Write()
方法將輸入數據複製到它的緩衝區,直到它填滿,然後你可以Write()
緩衝區到目的地TStream
並清除緩衝區。你的算法永遠不會知道它的區別。 TMemoryStream
和TFileStream
都將受益於額外緩衝 - 較少的較大寫入意味着更高效的內存分配和文件I/O。例如:
type
TMyBufferedStreamWriter = class(TStream)
private
fDest: TStream;
fBuffer: array[0..4095] of Byte;
fOffset: Cardinal;
public
constructor Create(ADest: TStream);
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
procedure FlushBuffer;
end;
。
uses
RTLConsts;
constructor TMyBufferedStreamWriter.Create(ADest: TStream);
begin
fDest := ADest;
end;
function TMyBufferedStreamWriter.Read(var Buffer; Count: Longint): Longint;
begin
Result := 0;
end;
function TMyBufferedStreamWriter.Write(const Buffer; Count: Longint): Longint;
var
pBuffer: PByte;
Num: Cardinal;
begin
Result := 0;
pBuffer := PByte(@Buffer);
while Count > 0 do
begin
Num := Min(SizeOf(fBuffer) - fOffset, Cardinal(Count));
if Num = 0 then FlushBuffer;
Move(pBuffer^, fBuffer[fOffset], Num);
Inc(fOffset, Num);
Inc(pBuffer, Num);
Dec(Count, Num);
Inc(Result, Num);
end;
end;
procedure TMyBufferedStreamWriter.FlushBuffer;
var
Idx: Cardinal;
Written: Longint;
begin
if fOffset = 0 then Exit;
Idx := 0;
repeat
Written := fDest.Write(fBuffer[Idx], fOffset - Idx);
if Written < 1 then raise EWriteError.CreateRes(@SWriteError);
Inc(Idx, Written);
until Idx = fOffset;
fOffset := 0;
end;
。
Writer := TMyBufferedStreamWriter.Create(RealStreamHere);
try
... write data to Writer normally as needed...
Writer.FlushBuffer;
finally
Writer.Free;
end;
你說的是內存流嗎? – 2012-03-29 17:56:55
如果數據量很大(比如超過200MB),那麼我推薦一個TFileStream,否則TMemoryStream會是最快最容易的方式。如果您選擇使用TFile | MemoryStream並且您需要保留信息(記錄計數等),請在Stream的開頭添加一個標題,並在每次更新後將光標位置重置爲開頭,讀取並覆蓋Stream的標題。位置:= Stream.Size; < - bam你在流的末尾,繼續追加數據。如果有任何刪除記錄的機會,那麼每條記錄都需要一個包含標誌的標題(Deleted:Boolean) – ComputerSaysNo 2012-03-29 18:23:39
@Dorin:我們使用套接字發送,所以TFileStream似乎不是一個選項。問題不在於如何使用stream + write來做到這一點,我們已經在使用它,問題是如果有一些方法可以更快地做到這一點。 – 2012-03-29 19:09:52