2010-10-11 11 views
7

Delphi 2009 i wyżej używa łańcuchów Unicode dla ich domyślnego typu ciągu. Dla mnie zrozumienie char unicode jest w rzeczywistości 16 bitową wartością lub 2 bajtami (uwaga: rozumiem, że istnieje możliwość 3 lub 4 bajtów char, ale weźmy pod uwagę najczęstszy przypadek). Jednak odkryłem, że TStringStream nie jest bardzo niezawodny w manipulowaniu tymi ciągami. Na przykład właściwość TStringStream.Size zwraca długość ciągu, a myślę, że powinna zwrócić liczbę bajtów zawartego łańcucha. Okay, możesz to zmienić samemu, ale najbardziej denerwuje mnie to, że TStringStream nie odczytuje lub zapisuje do bufora niezawodnie.Łańcuch Unicode i TStringStream

Proszę sprawdzić poniższy kod (jest to test DUnit i zawsze kończy się niepowodzeniem). Daj mi znać, gdzie jest problem (użyłem D2010 podczas testowania kodu).

procedure TestTCPackage.TestStringStream; 
const 
    cCount = 10; 
    cOrdMaxChar = Ord(High(Char)); 
var 
    B: Pointer; 
    SW, SR: TStringStream; 
    T: string; 
    i, j, k : Integer; 
    vStrings: array [0..cCount-1] of string; 
begin 
    RandSeed := GetTickCount; 
    for i := 0 to cCount - 1 do 
    begin 
    j := Random(100) + 1; 
    SetLength(vStrings[i], j); 
    for k := 1 to j do 
     // fill string with random char (but no #0) 
     vStrings[i][k] := Char(Random(cOrdMaxChar-1) + 1); 
    end; 

    for i := 0 to cCount - 1 do 
    begin 
    SW := TStringStream.Create(vStrings[i]); 
    try 
     GetMem(B, SW.Size * SizeOf(Char)); 
     try 
     SW.Read(B^, SW.Size * SizeOf(Char)); 

     SR := TStringStream.Create; 
     try 
      SR.Write(B^, SW.Size * SizeOf(Char)); 
      SR.Position := 0; 

      // check the string in the TStringStream with original value 
      Check(SR.DataString = vStrings[i]); 
     finally 
      SR.Free; 
     end; 
     finally 
     FreeMem(B); 
     end; 
    finally 
     SW.Free; 
    end; 
    end; 
end; 

Uwaga: Próbowałem już używać wystąpienie TMemoryStream jako pośrednik z zapisu/odczytu bufora i używać copyfrom z TStringStream przeczytać zawartość tego TMemoryStream z samym skutkiem awarii.

Odpowiedz

5

Po przeczytaniu this post (i dzięki Sergowi, który dostarczył odpowiedź na to pytanie) i odpowiedzi Barry'ego Kelly'ego, znalazłem problem. TStringStream w rzeczywistości domyślnie używa kodowania ASCII/ansysters. Więc nawet jeśli Twój domyślny typ łańcucha to unikod, o ile go nie powiesz, nie użyje kodowania Unicode. Osobiście uważam, że to dziwne. Może dla ułatwienia konwersji starych kodów.

Więc trzeba specjalnie ustawione kodowanie z TStringStream do TEncoding.Unicode manipulować ciąg Unicode poprawnie.

Oto mój zmodyfikowany kod, który przechodzi testu DUNIT jest:

procedure TestTCPackage.TestStringStream; 
const 
    cCount = 10; 
    cOrdMaxChar = Ord(High(Char)); 
var 
    B: Pointer; 
    SW, SR: TStringStream; 
    i, j, k : Integer; 
    vStrings: array [0..cCount-1] of string; 
begin 
    RandSeed := GetTickCount; 
    for i := 0 to cCount - 1 do 
    begin 
    j := Random(100) + 1; 
    SetLength(vStrings[i], j); 
    for k := 1 to j do 
     // fill string with random char (but no #0) 
     vStrings[i][k] := Char(Random(cOrdMaxChar-1) + 1); 
    end; 

    for i := 0 to cCount - 1 do 
    begin 
    SW := TStringStream.Create(vStrings[i], ***TEncoding.Unicode***); 
    try 
     GetMem(B, SW.Size); 
     try 
     SW.ReadBuffer(B^, SW.Size); 

     SR := TStringStream.Create('', ***TEncoding.Unicode***); 
     try 
      SR.WriteBuffer(B^, SW.Size); 
      SR.Position := 0; 

      // check the string in the TStringStream with original value 
      Check(SR.DataString = vStrings[i]); 
     finally 
      SR.Free; 
     end; 
     finally 
     FreeMem(B); 
     end; 
    finally 
     SW.Free; 
    end; 
    end; 
end; 

Ostatnia uwaga: Unicode nie gryzie! : D

5

Łańcuchy Unicode nie służą do przechowywania danych; użyj do tego celu TBytes. TStringStream używa powiązanego kodowania (właściwość Encoding) do kodowania ciągów znaków przekazanych za pomocą WriteString i dekodowania ciągów odczytanych za pomocą właściwości ReadString lub DataString.

+0

W rzeczywistości kod nie dotyczy przechowywania danych, ale po przeczytaniu odpowiedzi i innym wpisie, znalazłem problem. Domyślnie TStringStream używa ASCII/ansistring. Dziękuję Ci! – Luthfi

Powiązane problemy