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

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

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

文字列をバイナリ形式で保存する方法

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■91126 / inTopicNo.1)  文字列をバイナリ形式で保存する方法
  
□投稿者/ mode (1回)-(2019/05/31(Fri) 13:07:13)

分類:[.NET 全般] 

文字列と数値をバイナリ形式で保存する方法に関してですが、

            Dim TXT1 As String = "abc"
            Dim TXT2 As String = "def"

            Dim NUM1 As Integer = 1
            Dim NUM2 As Integer = 2


            Dim fs As New System.IO.FileStream(fileoutpath, System.IO.FileMode.Create, System.IO.FileAccess.Write)


            Using writer As New BinaryWriter(fs)

                writer.Write(System.Text.Encoding.Default.GetBytes(TXT1))
                writer.Write(System.Text.Encoding.Default.GetBytes(TXT2))

                writer.Write(NUM1)
                writer.Write(NUM2)

            End Using



            fs.Close()


のようにして、数値を保存する場合にはそのまま指定すれば良いだけですが、
文字列の場合には
System.Text.Encoding.Default.GetBytesを使わないとうまくいかないようです。

毎回、文字列だけこのコードを入れるのが面倒なのですが、
文字列出力の設定を一括でできないのでしょうか?


                Using writer As New BinaryWriter(fs, System.Text.Encoding.Default)

とすればうまくいくかと思ったのですが
うまくいきませんでした。




引用返信 編集キー/
■91127 / inTopicNo.2)  Re[1]: 文字列をバイナリ形式で保存する方法
□投稿者/ Hongliang (811回)-(2019/05/31(Fri) 13:45:33)
> System.Text.Encoding.Default.GetBytesを使わないとうまくいかないようです。
「うまくいく」の定義次第ではあります。
長さを示すプレフィクスが付くのがいいのならWriteに直接Stringを渡せばいいですし
(そうすることで、BinaryReaderでReadStringできるようになります)。
それが無用なら、確かにあらかじめ呼び出し側でByte()にしておく必要があります。

> 毎回、文字列だけこのコードを入れるのが面倒なのですが、
> 文字列出力の設定を一括でできないのでしょうか?
上述のようにBinaryWriterのString出力は長さを示すプレフィクスを付けるものなので、
その挙動が気に食わないのなら他の手立てをとる必要があります。
拡張メソッドを定義するのが一般的でしょうか。

Module BinaryWriterExtension
    <System.Runtime.CompilerServices.Extension> _
    Sub WriteRawString(ByVal writer As BinaryWriter, ByVal text As String)
        writer.Write(System.Text.Encoding.Default.GetBytes(text))
    End Sub
End Module

' こんな感じに呼び出せるようになる
writer.WriteRawString("hoge")

引用返信 編集キー/
■91131 / inTopicNo.3)  Re[1]: 文字列をバイナリ形式で保存する方法
□投稿者/ WebSurfer (1831回)-(2019/06/01(Sat) 13:14:25)
No91126 (mode さん) に返信

> System.Text.Encoding.Default.GetBytesを使わないとうまくいかないようです。

 その「うまくいかない」というのは Hongliang さんが No91127 に書かれたように、
String を引数に取る BinaryWriter.Wrire メソッドのオーバーロードを使うと、文字
長プレフィックスが追加されてしまうということだと思います。

が、それ以前に、エンコーディングと文字コードなどの基本的なことは理解されてい
るでしょうか?

そんなことは言われるまでもなく理解しているということでしたらこれ以下はスルー
してください。

> 文字列と数値をバイナリ形式で保存する方法に関してですが、

と書かれていますが、

(1) 同じ文字でもエンコーディングによってバイナリ形式(バイト列)は異なる

(2) 上記と、Int32 型のような数値のバイナリ形式(ビット表現)は異なもの

・・・ということは理解されていますか?

まず (1) の件ですが、同じ文字列を異なるエンコーディングでバイト列に変換して見
れば分かります。

例えば以下のコードのように、"abcあいう&#256;" という文字列(最後の文字 '&#256;' は 
Shift_JIS にないもの)を、Encoding.Default(日本語 OS では Shift_JIS)、
utf-8、Unicode (little endian) という異なるエンコーディングでバイト列に変換し
てみてください。

string testString = "abcあいう&#256;";

Console.WriteLine("\nEncoding.Default:");
Byte[] bytes = Encoding.Default.GetBytes(testString);
foreach (Byte b in bytes)
{
    Console.Write("[{0:X2}]", b);
}

Console.WriteLine("\nEncoding.UTF8:");
bytes = Encoding.UTF8.GetBytes(testString);
foreach (Byte b in bytes)
{
    Console.Write("[{0:X2}]", b);
}

Console.WriteLine("\nEncoding.Unicode:");
bytes = Encoding.Unicode.GetBytes(testString);
foreach (Byte b in bytes)
{
    Console.Write("[{0:X2}]", b);
}

結果は以下の通りとなります。これを見ると、エンコーディングを意識しないでバイト
列に変換するのは意味がないということが分かると思います。

Encoding.Default:
[61][62][63][82][A0][82][A2][82][A4][3F]
Encoding.UTF8:
[61][62][63][E3][81][82][E3][81][84][E3][81][86][C4][80]
Encoding.Unicode:
[61][00][62][00][63][00][42][30][44][30][46][30][00][01]

注: Encoding.Default の最後の [3F] は '?' に該当します('&#256;' は Shift_JIS にない
から)。他のエンコーディングでは正しくバイト列に変換されています。

そして (2) の件ですが、writer.Write(NUM1) は BinaryWriter.Write メソッド (Int32) 
になります。

MSDN ライブラリでは "現在のストリームに 4 バイト符号付き整数を書き込み" と書いて
ありますが、具体的には Int32 型の数値のビット表現がファイルに書き込まれます。

NUM1 = 1 であればファイルに書き込まれた結果をバイナリエディタでみると 01 00 00 00 
というように 4 バイトで 1 のビット表現になっているはずです。これと、上の文字列は全
く異質なものということは理解していただけるでしょうか?

引用返信 編集キー/
■91132 / inTopicNo.4)  Re[2]: 文字列をバイナリ形式で保存する方法
□投稿者/ Jitta (443回)-(2019/06/01(Sat) 14:45:18)
そもそも、ファイルは全てバイナリー。
文字と対応するコードのみで構成されている時にテキスト ファイルという。
Seializableなクラスにまとめて、BinaryFormatterで出力、とか。
Stringに対して拡張メソッドを宣言するとか。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ