WideString(Unicode)をTMemoryStreamに展開したい

解決


aioi  2012-07-30 09:28:36  No: 42668

WideString(Unicode)をTMemoryStreamに展開する方法がわかりません。
以下のコードを書いて試していますが、上手くファイル出力できません。
(ゴミが入ってしまう?)

procedure OutFile_UNI(OutputContent, OutputFileName : WideString);
var
  Buffer: PByte;
  len   : dWord;
  msIn  : TMemoryStream;
  fsOut : TFileStream;
  endFlg: Boolean;
begin

//**** ここがうまくいかない? ****
  // WideStringの値をTMemoryStreamに保持する
  msIn := TMemoryStream.Create;
  msIn.Write(PWChar(OutputContent)^, Length(OutputContent)*sizeof(PWChar) );
  msIn.Position := 0;
//**********************************

  fsOut:= TFileStream.Create(OutputFileName, fmCreate);
  try
    GetMem(Buffer, 512);
    repeat
      endFlg := (msIn.Position >= msIn.Size);
      if endFlg then break;
      len := msIn.Read(Buffer^, 512);

      // **** バッファ(Buffer)に対する加工処理 ****

      fsOut.Write(Buffer^, len);
    until endFlg;
     FreeMem(Buffer, 512);
  finally
    msIn.Free;
    fsOut.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  strTmp : WideString;
begin
  strTmp := '文字列を書き込み!'+#13#10+'書き込みテストです';

  // [NG] Unicodeファイルの出力
  OutFile_UNI(strTmp, 'unicode.txt');
end;

TMemoryStreamからTFileStreamにバッファを格納しているのは、特別なバッファ処理があるためで、単にUnicode文字列をファイル出力したいのではありません。
ですので何とかWideStringの値をTMemoryStreamに格納したい次第です。

ちなみにString(SJIS)の場合は上手く行きました。

procedure OutFile_SJIS(OutputContent, OutputFileName : String);
var
  Buffer: PByte;
  len   : dWord;
  msIn  : TMemoryStream;
  fsOut : TFileStream;
  endFlg: Boolean;
begin
  // Stringの値をTMemoryStreamに保持する
  msIn := TMemoryStream.Create;
  msIn.Write(PChar(OutputContent)^, Length(OutputContent) );
  msIn.Position := 0;

  fsOut:= TFileStream.Create(OutputFileName, fmCreate);
  try
    GetMem(Buffer, 512);
    repeat
      endFlg := (msIn.Position >= msIn.Size);
      if endFlg then break;
      len := msIn.Read(Buffer^, 512);

      // **** バッファ(Buffer)に対する加工処理 ****

      fsOut.Write(Buffer^, len);
    until endFlg;
    FreeMem(Buffer, 512);
  finally
    msIn.Free;
    fsOut.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  strTmp : String;
begin
  strTmp := '文字列を書き込み!'+#13#10+'書き込みテストです';

  // [OK] SJISファイルの出力
  OutFile_SJIS(strTmp, 'unicode.txt');
end;

環境はTurbo Delphiです。
すみませんが、お知恵をお借り出来れば幸いです。


DEKO  2012-07-30 13:20:58  No: 42669

こんにちは。

"WideString 文字列をデータとして書き出す" のではなく、
"Unicode (UTF-16LE) のテキストファイルとして書き出す" のであれば、
ファイル先頭の BOM が足りないのではないでしょうか?

  fsOut:= TFileStream.Create(OutputFileName, fmCreate);
  try
    fsOut.Write(#$FF#$FE, 2); // <- BOM を追加
    ...

[Unicode (Delphi VCL FAQ)]
http://ht-deko.minim.ne.jp/tech013.html


aioi  2012-07-30 19:05:38  No: 42670

DEKO様
早速の書き込みありがとうございました。

> Unicode (UTF-16LE) のテキストファイルとして書き出す

はい、最終的にUTF-16で書き出すことになります。

> ファイル先頭の BOM が足りないのではないでしょうか?

BOMの追加のコードを埋め込みましたが、やはりうまくいきません。

うまくいかない現象としては、サンプルコードを実行し、
ファイルの中身を確認すると、以下のようになってしまいます。
------
文字列を書き込み!
書き込みテストですxxxxxxxxx
------
(xxxxxxxxxの部分は文字化けで、文字コードはUTF-16)

個人的に、サンプルコードの以下の箇所の
WideStringの値をTMemoryStreamにWirteしている箇所が
良くないと思っていますが、いかがでしょうか。
------
msIn.Write(PWChar(OutputContent)^, Length(OutputContent)*sizeof(PWChar) );
------
(サイズの指定がおかしい?)

> [Unicode (Delphi VCL FAQ)]

Unicodeの詳しい解説のリンクありがとうございました。
私はUnicodeに対し詳しいわけではありませんので、
他のサイトも含めて少しずつ仕組みを理解したいと思います。

度々すみませんが、お知恵をお借り出来れば幸いです。


KHE00221  2012-07-30 19:32:56  No: 42671

msIn.Write(PWChar(OutputContent)^, Length(OutputContent)*sizeof(PWChar) );

PWChar じゃなくて WChar だろ


aioi  2012-07-30 20:49:26  No: 42672

KHE00221様
書き込みありがとうございました。

ご指摘の通り修正しましたところ、正常に動作しました!

msIn.Write(PWChar(OutputContent)^, Length(OutputContent)*sizeof(PWChar) );

msIn.Write(PWChar(OutputContent)^, Length(OutputContent)*sizeof(WChar) );

本当にありがとうございました、助かりました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加