2010-04-01 180 views
4

我正在將D2006程序轉換爲D2010。我的數據庫中每個字符的字符串都有一個字節的值,我需要將它加載到一個具有LoadFromStream的控件中,所以我的計劃是將該字符串寫入一個流,並將其用於LoadFromStream。但它沒有奏效。在研究這個問題時,我看到一個問題,告訴我我並不真正瞭解如何從AnsiString轉換爲Unicode字符串。下面是一段獨立代碼,它說明了我對以下內容感到困惑的問題:將AnsiString轉換爲Unicode字符串

procedure TForm1.Button1Click(Sender: TObject); {$O-} 
var 
    sBuffer: String; 
    oStringStream: TStringStream; 
    sAnsiString: AnsiString; 
    sUnicodeString: String; 
    iSize1, 
    iSize2: Word; 
begin 
    sAnsiString := '12345'; 
    oStringStream := TStringStream.Create(sBuffer); 
    sUnicodeString := sAnsiString; 
    iSize1 := StringElementSize(sAnsiString); 
    iSize2 := StringElementSize(sUnicodeString); 
    oStringStream.WriteString(sUnicodeString); 
end; 

如果你打破的最後一行,並檢查oStringStream的字節屬性,你會看到,它看起來像這樣:

Bytes (49 {$31}, 50 {$32}, 51 {$33}, 52 {$34}, 53 {$35} 

我期待它可能看起來像

(49 {$31}, 00 {$00}, 50 {$32}, 00 {$00}, 51 {$33}, 00 {$00}, 
52 {$34}, 00 {$00}, 53 {$35}, 00 {$00} ... 

顯然我的期望是錯誤的。但是,那麼,如何將一個AnsiString轉換爲unicode?

我沒有從LoadFromStream中獲得正確的結果,因爲它一次從流中讀取兩個字節,但它所接收的數據不是以這種方式排列的。我應該怎麼做才能給LoadFromStream一個基於unicode字符串的格式良好的數據流?

謝謝你的幫助。

+3

我不相信問題中有足夠的信息來啓用有意義的答案。涉及的變量是什麼類型?就編譯器生成的代碼中觸發的任何自動轉換而言,這將具有潛在的重要性。特別是oPayGrid的類型是什麼?此對象上存在sStream屬性表明它不是標準的VCL流。理想情況下,我希望將問題中的代碼示例重新構建爲一個獨立的工作示例,用於演示不需要進一步解釋/占卜的行爲。 – Deltics 2010-04-01 01:24:00

+0

給Aotearoa冰雹! 對不起。我試圖避免用無益的細節來解決問題。我想我太成功了。 oPaygrid是一個類(TObject)。 oPaygrid.sStream是一個名字很差的AnsiString。 sUnicodeString是一個Delphi字符串,默認情況下它是一個unicode字符串。 iSize1和iSize2是整數。 我的問題主要是概念。當AnsiString被強制轉換爲unicode字符串時,我應該期望在unicode字符串中每個字符看到兩個字節嗎?我沒有看到這一點,它似乎是阻止我用LoadFromStream成功加載控件。 – jrodenhi 2010-04-01 01:41:48

+0

您不應該使用StringElementSize()。只有在您的代碼是從半遷移的C++ Builder模塊中調用時纔是必需的。賦值'sUnicodeString:= sAnsiString'將字符串的有效載荷更正爲Char = WideChar,因此對StringElementSize的調用將始終爲您的UnicodeString返回SizeOf(AnsiChar)和SizeOf(Char)。 SizeOf(AnsiChar)/ SizeOf(Char)也快很多,閱讀和理解起來更容易,寫起來也更簡短。 – 2010-04-01 05:30:12

回答

5

oStringStream.WriteString參數的類型是什麼?如果它是AnsiString,那麼你有一個從Unicode到Ansi的隱式轉換,這就解釋了你的例子。


更新:現在真正的問題是TStringStream如何在內部存儲數據。 在下面的代碼示例(2009的Delphi)

procedure TForm1.Button1Click(Sender: TObject); 
var 
    S: string; 
    SS: TStringStream; 

begin 
    S:= 'asdfg'; 
    SS:= TStringStream.Create(S); // 1 byte per char 
    SS.WriteString('321'); 
    Label1.Caption:= SS.DataString; 
    SS.Free; 
end; 

TStringStream內部使用默認的系統ANSI編碼(每字符1個字節)。 構造函數和WriteString過程將字符串參數從unicode轉換爲ANSI。

要覆蓋此行爲,您必須聲明編碼明確地在構造函數中:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    S: string; 
    SS: TStringStream; 

begin 
    S:= 'asdfg'; 
    SS:= TStringStream.Create(S, TEncoding.Unicode); // 2 bytes per char 
    SS.WriteString('321'); 
    Label1.Caption:= SS.DataString; 
    SS.Free; 
end; 
+0

sBuffer聲明爲: var sBuffer:UnicodeString; – jrodenhi 2010-04-01 04:11:36

0

我想你想使用:

LoadFromStream(stream, TEncoding.ASCII); 

如果你的單字節的文字是不是ASCII而是基於在代碼頁上,那麼這可能工作:

LoadFromStream(stream, TEncoding.GetEncoding(1252)); 

其中「1252」是代碼頁,喲你的單字節文本是基於。

+0

LoadFromStream是來自TMS的AdvStringrid的一種方法。它只需要一個參數。 – jrodenhi 2010-04-01 04:17:31

+0

我不使用TMS,但也許TMS的TTntStringGrid在它們的Unicode組件包中可能能夠爲你做到。請參閱:http://www.tmssoftware.com/site/tmsuni.asp否則,我建議您聯繫TMS並告訴他們您的問題,他們可能會將第二個參數添加到他們的LoadFromStream中,以使Delphi 2009+ Unicode兼容。 – lkessler 2010-04-01 04:26:22

+0

這似乎不是網格的問題。請參閱我對原始文章的編輯。它似乎並沒有將一個AnsiString強制轉換爲unicode來改變字符串的內部格式。 – jrodenhi 2010-04-01 05:27:59

0

流格式在很大程度上取決於TStringStream.Encoding。在你的例子中,使用的代碼頁應該與sBuffer相同(參見TStringStream.Create的實現)。

由於oStringStream.WriteString(sUnicodeStream);似乎保存爲單個字節,我假設sBuffer是一個Ansistring或RawByteString。

現在......爲什麼閱讀失敗......您還沒有向我們提供如何在該流中回讀的示例。

+0

所以,像我一樣,你期望如果sUnicodeStream被聲明爲一個UnicodeString,你會看到一個由每個字符兩個字節組成的字符串。如果你嘗試了我新編輯的示例代碼,你會發現它顯然不能這樣工作。 – jrodenhi 2010-04-01 05:45:25

+0

塞爾格是正確的... TStringStream只檢查ansistring版本中的代碼頁。 – 2010-04-01 13:45:13