2013-05-13 4 views
-1

Я использую эти реализации, которые я нашел в другом сообщении на SO. Но при чтении строки иногда ReadStreamStr помещает лишние символы в строку. Поэтому я отправляю свою реализацию здесь, чтобы проверить и утвердить ее, и если есть ошибка, исправлена.Delphi ReadStreamStr, проверка выполнения WriteStreamStr

function ReadStreamStr(Stream: TStream): string; 
{ returns a string from the stream } 
var 
    LenStr: Integer; 
begin 
    Result := ''; 
    { get length of string } 
    LenStr := ReadStreamInt(Stream); 
    { set string to get memory } 
    SetLength(Result, LenStr); 
    { read characters } 
    Stream.Read(Result[1], LenStr); 
end; 

procedure WriteStreamStr(Stream: TStream; Str: string); 
{ writes a string to the stream } 
var 
    StrLen: Integer; 
begin 
    { get length of string } 
    StrLen := ByteLength(Str); 
    { write length of string } 
    WriteStreamInt(Stream, StrLen); 
    if StrLen > 0 then 
    { write characters } 
    Stream.Write(Str[1], StrLen); 
end; 

спасибо.

+2

Я бы лично использовать псевдо-код [ 'как this'] (HTTP: // pastebin.com/RbHpFpaP). – TLama

+0

@TLama: Что-то не так с этим кодом. он не работает для меня. Его чтение за пределами строки. Использование: Delphi XE2. –

ответ

4

Integer, что написано перед персонажами является числа байт, но ReadStreamStr() интерпретирует его как числа символов вместо. В D2007 и ранее, где string Ansi, это работает отлично. Но в D2009 и более поздних версиях, где string является Unicode, это не работает. Предполагая, что вы используете D2009 +, это означает, что ReadStreamStr() выделяет в два раза больше памяти, чем должно быть, но только заполняя ее половину, оставляя вторую половину неинициализированной. Вы не принимаете SizeOf(Char) во внимание при чтении (но ByteLength() делает при написании).

Попробуйте это:

function ReadStreamStr(Stream: TStream): string; 
{ returns a string from the stream } 
var 
    LenStr: Integer; 
    LeftOver: array[0..SizeOf(Char)-1] of Byte; 
begin 
    Result := ''; 
    { get length of string } 
    LenStr := ReadStreamInt(Stream); 
    { set string to get memory } 
    SetLength(Result, LenStr div SizeOf(Char)); 
    if LenStr > 0 then begin 
    { read characters } 
    Stream.ReadBuffer(Result[1], LenStr); 
    { just in case the length was not even } 
    LenStr := LenStr mod SizeOf(Char); 
    if LenStr > 0 then 
     Stream.ReadBuffer(LeftOver[0], LenStr); 
    end; 
end; 

В качестве альтернативы:

function ReadStreamStr(Stream: TStream): string; 
{ returns a string from the stream } 
var 
    LenStr: Integer; 
    Buf: TBytes; 
begin 
    Result := ''; 
    { get length of string } 
    LenStr := ReadStreamInt(Stream); 
    if LenStr > 0 then begin 
    { get memory } 
    SetLength(Buf, LenStr); 
    { read characters } 
    Stream.ReadBuffer(Buf[1], LenStr); 
    { convert to string } 
    Result := TEncoding.Unicode.GetString(Buf); 
    end; 
end; 

В любом случае, имейте в виду, что если поток данных был написан в D2007 или раньше, но читается D2009 или более поздней версии, то этот код не будет работать как есть. Вы должны пойти на подход TBytes, но используйте более подходящий TEncoding для декодирования, например TEncoding.Default.

Лично я бы предпочел, чтобы вместо чтения/записи строки как UTF-8 с самого начала:

function ReadStreamStr(Stream: TStream): UTF8String; 
{ returns a string from the stream } 
var 
    LenStr: Integer; 
begin 
    Result := ''; 
    { get length of string } 
    LenStr := ReadStreamInt(Stream); 
    { set string to get memory } 
    SetLength(Result, LenStr); 
    if LenStr > 0 then 
    { read characters } 
    Stream.Read(PAnsiChar(Result)^, LenStr); 
end; 

procedure WriteStreamStr(Stream: TStream; const Str: UTF8tring); 
{ writes a string to the stream } 
var 
    StrLen: Integer; 
begin 
    { get length of string } 
    StrLen := Length(Str); 
    { write length of string } 
    WriteStreamInt(Stream, StrLen); 
    if StrLen > 0 then 
    { write characters } 
    Stream.Write(PAnsiChar(Str)^, StrLen); 
end; 
+0

Спасибо, Реми. Ваш фрагмент кода очень полезен. –

Смежные вопросы