C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 45 を表示中)
■23999 / )  Re[3]: MemoryStreamとXmlWriter
□投稿者/ kobachi (2回)-(2008/08/26(Tue) 14:17:03)
kobachi さんの Web サイト
やじゅ様 および なちゃ様
ご返答ありがとうございます。

質問時に掲載しましたコードは同じ状況が発生する最低限のコードでした。
実際にはEncodingを指定し、XmlWriterSettingsのEncodingと
GetString()に用いるEncodingを同じものにしていました。

>ところで、?とは何で見たときに?なんでしょう?

確認用出力は、Console.WriteLine()を使いました。
(が、問題はここにもありました!)

▼----------【Encodingを指定したつもりのコードここから】----------▼
Encoding utf8 = Encoding.UTF8;//= new UTF8Encoding();
using(MemoryStream stream = new MemoryStream()){
	XmlWriterSettings settings = new XmlWriterSettings();
	settings.Encoding = utf8;
	using(XmlWriter writer = XmlWriter.Create(stream, settings)){
		//中略
	}
	Console.WriteLine(utf8.GetString(stream.ToArray()));
}
▲----------【Encodingを指定したつもりのコードここまで】----------▲

BOMの可能性については上記のコードで解決したつもりでしたが・・・
実は違いました。


----------
■追試
----------

今まではVisual Studioだけでデバッグしていましたが、
文字エンコードが絡むことなので、
「信頼のおける」別のソフトを使って追試を行うことにしました。

秀丸エディタでUTF8 BOM付きのテキストを作成し、
バイナリエディタBzで作成したテキストを開いて、
バイナリ列をbyte[]に直接書き写したものをEncoding.UTF8でGetString()すると
先頭に「?」が挿入される現象が再現されます。
→やはり問題はBOMのようです

次に、日本語とアラビア語が混在したstringのインスタンスを持たせ、
EncodingをEncoding.Unicode(UTF16)に変更。
それを上記のコードでSerialize()→GetString()を試すと文字化けしました!
→XmlWriteSettings.Encodingが無視され、常にUTF-8でエンコードされているようです

さらに、Encoding.UTF8でも、System.Diagnostics.Debug.WriteLine()だと、
「?」が挿入されないことにも気づきました。
→あれ?

・・・という状況説明だけでは何も伝わらないと思うので、
同じ問題に遭遇した人(いるのか?)のためにまとめて起きたいと思います。


----------
■まとめ
----------

この問題の原因には、下記の2つの仕様が関わっているようです。

1. XmlWriterSetting.Encodingは、
  XMLのプリアンブルに含まれるencoding属性を書き換えるだけで、
  StreamにどのEncodingで書き込むかというのを制御しないという仕様。
  Encodingを指定するためには、StreamWriterのインスタンスを渡す必要がある。
    ▼----------【正常に動作するコードここから】----------▼
    Encoding utf8 = Encoding.UTF8;//= new UTF8Encoding();
    using(MemoryStream stream = new MemoryStream()){
        using(StreamWriter wrapper = new StreamWriter(stream, utf8)){
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = utf8;
            using(XmlWriter writer = XmlWriter.Create(wrapper, settings)){
                //中略
            }
            Console.WriteLine(utf8.GetString(stream.ToArray()));
        }
    }
    ▲----------【正常に動作するコードここまで】----------▲

2. Console.WriteLine()は日本語版WindowsではCP932への変換を経てVisual Studioに伝わるため、
  Unicode文字列(BOMも)をConsole.WriteLine()で出力すると正常に表示されないという仕様。
  参考:http://oshiete1.goo.ne.jp/qa684358.html

ということが分かりました。

お二方のご指摘通り問題はBOMでした。
Encodingが絡む場合はかなり注意してコードを組まないといけないんですね・・・

どうもありがとうございました。

解決済み
返信 編集キー/


管理者用

- Child Tree -