Delphi中TMemoryStream读取TBytes与字节数组为何存在差异?
Hey there, let's break down that frustrating TStream.Read behavior you're seeing with your Z85 encoder in Delphi 2010. I've run into my share of stream quirks in this version, so let's walk through the most likely culprits and fixes.
First, let's recap your setup to make sure we're on the same page: you've got a stream-based Z85Encode function, plus an overload that wraps TBytes into a TBytesStream to spit out a string. The problem is that TStream.Read isn't acting like the docs say it should. Here's where to look:
1. You're forgetting to reset stream positions
This is the #1 gotcha with TBytesStream (and all TStream descendants). When you write to a stream or initialize it from a TBytes, the Position property stays at the end of the data by default. If you call Read right away, you're reading from the EOF, so it returns 0 bytes—making it seem like Read is broken.
Fix this in your overload function by explicitly setting Position to 0 before reading or encoding:
function Z85Encode(b: TBytes): string; var InputStream, OutputStream: TBytesStream; ReadBytes: Integer; begin InputStream := TBytesStream.Create(b); OutputStream := TBytesStream.Create; try // Critical: Reset input stream to start before encoding InputStream.Position := 0; Z85Encode(InputStream, OutputStream); // Reset output stream to read the encoded result OutputStream.Position := 0; SetLength(Result, OutputStream.Size); ReadBytes := OutputStream.Read(Result[1], OutputStream.Size); // Trim result to actual bytes read (in case of edge cases) SetLength(Result, ReadBytes); finally InputStream.Free; OutputStream.Free; end; end;
2. Misinterpreting the Read return value
Delphi's TStream.Read returns the actual number of bytes read, not the number you requested. The docs say it reads up to the requested count, but if the stream has less data left (or you're already at EOF), it returns fewer bytes. A lot of developers assume it always grabs the full chunk, which leads to confusion.
For Z85, which processes 4-byte chunks, you need to loop until Read returns 0 to handle all data—including partial chunks if your input isn't 4-byte aligned:
function Z85Encode(input, output: TStream): integer; var Chunk: array[0..3] of Byte; BytesRead: Integer; EncodedChars: array[0..4] of Char; begin Result := 0; BytesRead := input.Read(Chunk, SizeOf(Chunk)); while BytesRead > 0 do begin // Handle partial chunks (pad with zeros if needed for Z85) if BytesRead < 4 then FillChar(Chunk[BytesRead], 4 - BytesRead, 0); // Encode the 4-byte chunk to 5 Z85 chars EncodeSingleZ85Chunk(Chunk, EncodedChars); output.Write(EncodedChars, SizeOf(EncodedChars)); Inc(Result, 5); BytesRead := input.Read(Chunk, SizeOf(Chunk)); end; end;
3. TBytesStream-specific quirks in Delphi 2010
While TBytesStream is similar to TMemoryStream, it has a key difference: when you create it from a TBytes, it references the original array directly (no copy in some scenarios). If the original TBytes gets modified elsewhere, it can mess up your stream data. Also, in 2010, TBytesStream.Read can behave oddly with zero-length streams or odd-sized data—always validate input.Size and input.Position before reading.
Quick Debug Steps
To narrow it down further:
- Add debug logging to track
input.Position,input.Size, and the return value of everyReadcall. This will show if you're reading from the wrong spot or getting partial reads when you don't expect them. - Test with a small, known input (like 4 bytes of
$00)—the Z85 output should be"0000". If this works, your issue is likely with handling non-aligned input or position management. - Check if any other code is modifying the stream's
Positionbefore yourReadcall—sometimes accidental stream position changes are the culprit.
Hope this helps you track down the issue!
内容的提问来源于stack exchange,提问作者Gerald Me

