ファイルをバイナリで読み込むには??

解決


π  2004-09-22 12:15:28  No: 116413

はじめましてこんばんは!質問させていただきます><;
テキストファイルなどを読み込んで、16進数でダンプしたいのですが、
どのようにすればよいのでしょうか?

実際にプログラムを書くとなると難しいのですね><過去ログから検索したのですがどうも見つからなかったみたいなので書き込ませてもらいました。初歩的な質問かと思いますがよろしくお願いしますm(。。)m


魔界の仮面弁士  2004-09-22 12:26:54  No: 116414

ファイルのバイナリでの読み込みに関しては、
VB.NET なら、System.IO.FileStreamクラス、
VBScript なら、ADODB.Streamオブジェクト、
旧VB なら、Openステートメントについて調べてみてください。

なお、16進数での表現には、Hex関数などを利用できます。


π  2004-09-22 12:37:19  No: 116415

返信ありがたいです><
System.IO.FileStreamについて今調べています!初心者の私にとってはプログラムに関してのボキャブラリが少ないので検索できなかったです。。

たとえば他の検索キーワードで「System.IO.FileStream」とかあっても、その人が定義したのかな?とか色々考えてしまって。。

寝るまでがんばるぞお☆


π  2004-09-22 13:00:40  No: 116416

TextBox1にダイアログから指定して読み込んで、ボタンを押すと出力するようにしたんですけれども、長い文章のテキストだとエラーがでてしまうんですが・・・

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        'Base64でバイト型配列に戻す文字列
        Dim s As String = TextBox1.Text

        'バイト型配列に戻す
        Dim bs() As Byte = System.Convert.FromBase64String(s)

        'ファイルに保存する
        '保存するファイル名
        Dim outFileName As String = "d:\h.txt"
        'ファイルに書き込む
        Dim outFile As New System.IO.FileStream(outFileName, System.IO.FileMode.Create, System.IO.FileAccess.Write)

        outFile.Write(bs, 0, bs.Length)
        outFile.Close()
        MsgBox("ok")

    End Sub


魔界の仮面弁士  2004-09-22 18:07:12  No: 116417

> 'Base64でバイト型配列に戻す文字列

あれれ? なんだか、質問の内容とやっている事が、全く一致していないような…。

とりあえず、単純に「Byte配列を16進数でダンプする」だけであれば、
BitConverterクラスのToString()メソッドが使えます。

しかし、提示されたコードを見る限り、今回の場合は、
バイナリを16進数でダンプする事が目的なのではなく、
BASE64変換を行いたかった、ということのようですね。

> TextBox1にダイアログから指定して読み込んで、
提示されたコードには、ダイアログを表示している部分が見当たりません。
というより、これは「ファイルからデータを読み込んでいる」のではなく、
「TextBoxから読み込んだデータをファイルに書き込んでいる」コードですよね。

> 長い文章のテキストだとエラーがでてしまうんですが・・・
具体的には、何文字以下であれば正常に処理されて、
何文字以上であれば、エラーになるのでしょうか?
そしてエラーになる場合、どのようなエラーが発生するのでしょうか?

とりあえず、提示されたコードの場合、TextBoxの内容をUU エンコードされた文字列と
みなして変換しておられるようですが、この場合、空白文字を除いた文字列の長さが、
4の倍数になっていない場合、変換エラー(FormatException例外)が発生する可能性があります。


π  2004-09-22 20:47:08  No: 116418

おはようございます!返信ありがとうございます。

コードを貼り付けてどんな処理をしてるんだろうって所から始めてるのでまだよくわからないところが多々あるんですよね・・。

ダイアログのところは、
Private Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem2.Click
        Dim alltext, linetext As String

        dialog1.Filter = "textfiles(*.*)|*.*"
        dialog1.ShowDialog()
        If dialog1.FileName <> "" Then
            Try
                FileOpen(1, dialog1.FileName, OpenMode.Binary)
                Do Until EOF(1)
                    linetext = LineInput(1)
                    alltext = alltext & linetext & vbCrLf
                Loop
                Label1.Text = dialog1.FileName
                TextBox1.Text = alltext
                TextBox1.Enabled = True
 
            Catch ex As Exception
                MsgBox("開けない")
            Finally
                FileClose(1)
            End Try
        End If
        TextBox1.Text = alltext

    End Sub
でやっていました。ファイルを読み込む時点に問題があるのでしょうか。。
これから学校いってきます!!


+id_rsa  2004-09-23 08:30:16  No: 116419

VB6なら、↓コレでいけるんだけど・・・参考になるかな?
Dim iFile                   As Integer
Dim bFile()                 As Byte
Dim Index                   As Long

    bFile = ""
    iFile = FreeFile
    Open FileName For Binary Access Read Write Lock Read Write As #iFile
    bFile = InputB(LOF(iFile), #iFile)
    Close iFile
    With Text1
        For Index = LBound(bFile) To UBound(bFile)
            .SelText = Right$("0" & Hex$(bFile(Index)), 2)
            DoEvents: Me.Caption = Index & "/" & UBound(bFile)
        Next Index
    End With


π  2004-09-23 09:32:57  No: 116420

いまただいまですっ!返信おくれてすみません^^c
今日はVB.netの本を借りてきました^^vでも入門の本には書いてなさそうですが・・!
+id_rsaさんコードありがとうございます!プログラムをみるとこうやってつかうのかぁって、、なんとなくわかる気がします!
もうすこし調べてみますっ!!


π  2004-09-23 11:00:29  No: 116421

Dim srFile As New System.IO.BinaryReader("d:\test.txt",  System.Text.UTF8Encoding.Default)

とすると、"d:\test.txt"のところにアンダーラインがつくのですが、バイナリを読むときって、system.io.binaryreaderじゃないんですか??


π  2004-09-23 12:46:24  No: 116422

魔界の仮面弁士さんへ
いまになって昨日書き込んだプログラムをみると、、、ご指摘の通り全然違う気がしました^^;それでも自分なりに調べたつもりだったんですが・・恥ずかしいです。。

文字列を読み込むところまではやっとできました;;読み込んだファイルを、「00 FF 00 36 EF A0 0C」というように表示させたいのですが、それにはByte型の配列にする必要があるんですよね?


π  2004-09-23 12:56:21  No: 116423

連続書き込みですみません><誤って途中で送信を押しちゃったみたいです!ごめんなさい。

読み込んだファイルを「00 FF 00 36 EF A0 0C」というようにするには、文字列を数字?に変換するって事なんでしょうか。。そこから16進数に戻す処理が必要なんでしょうか。。

調べてみると、system.bitconverter.getbyteというのが「指定したデータをバイト配列に変換します。」とあったのでそれらしいとおもったのですがどうもうまくいかないんです。。

まったく的はずれなのかな・・(@o@)とおもったり・・ながながとごめんなさいです。。


魔界の仮面弁士  2004-09-23 18:45:30  No: 116424

[2004/09/22(水) 11:47:08]
> コードを貼り付けてどんな処理をしてるんだろうって所から始めてるので
結局のところ、「BASE64」での変換処理は、行いたいのでしょうか? それとも行いたく無いのでしょうか?

[2004/09/23(木) 02:00:29]
> バイナリを読むときって、system.io.binaryreaderじゃないんですか??
……私は、「FileStreamクラス」と回答したはずですけれども。(^_^;)

> Dim srFile As New System.IO.BinaryReader("d:\test.txt",  System.Text.UTF8Encoding.Default)

BinaryReaderは、ファイルから読み取るためのクラスではなく、
Streamから読み取るためのクラスです。
ヘルプで、このクラスのコンストラクタを確認してみてください。

つまりBinaryReaderの場合、文字列ではなく、FileStreamやMemoryStreamなどを渡す必要がある、という事です。

[2004/09/23(木) 03:46:24]
> 読み込んだファイルを、「00 FF 00 36 EF A0 0C」というように表示させたいのですが、それにはByte型の配列にする必要があるんですよね?
Byte配列以外(たとえば、Char配列やStringから)でも、そうした表記は可能です。
とはいえ、Byte配列にした方が簡単でしょうね。

で、Stringで読み込んでからByte配列にするのは、効率が悪いです。
それに、テキスト以外のデータが相手だと、この方法は使えませんし。

今回の場合は、最初からByte配列のまま読み込んで、それをBitConverterで変換した方が楽でしょう。

[2004/09/23(木) 03:56:21]
> 文字列を数字?に変換するって事なんでしょうか。
数値の表し方の問題なので、「変換」というのはちょっと違うかも。
http://www.gj.il24.net/~nakasima/prog/radix/index.htm

> system.bitconverter.getbyteというのが「指定したデータをバイト配列に変換します。」
確かにこのメソッドは、他のデータ型(IntegerやDoubleなど)をByte配列に変換できます。
ただしStringの場合は、文字コードのエンコーディングの指定の関係上、このメソッドではなく、System.Text.Encodingを使って、文字列→Byte()変換を行うことになります。

とはいえ、先に書いたように、ファイルを文字列に読み取って、それをByte配列に変換するのは無駄が多いので、直接、ファイルをバイナリで読み取った方が手っ取り早いでしょうけど。


π  2004-09-24 00:16:06  No: 116425

>結局のところ、「BASE64」での変換処理は、行いたいのでしょうか? それとも行いたく無いのでしょうか?

なんかまぎらわしくてすみません・・。「BASE64」での変換処理は全くしたくないんです><。。ただ、このときはヘルプをみても何を言っているのかまったく分からずネットで検索してバイト型配列にしているところを貼り付けていました・・。

>私は、「FileStreamクラス」と回答したはずですけれども。(^_^;)

はい・・・わかってはいたんですが・・System.IO.FileStreamって繋げるのがまったくわからなかったんです・・。いまはだんだんとつかめてきましたが;;

Dim opFile As New System.IO.FileStream(OpenFileDialog1.FileName, IO.FileMode.Open)

にあるように  New  ってどういう意味を持つのでしょうか??

>とはいえ、先に書いたように、ファイルを文字列に読み取って、それをByte配列に変換するのは無駄が多いので、直接、ファイルをバイナリで読み取った方が手っ取り早いでしょうけど。

はい・・本当すいません。。

        OpenFileDialog1.ShowDialog()
        Dim bi() As Byte

        If OpenFileDialog1.FileName <> "" Then
            Dim opFile As New System.IO.FileStream(OpenFileDialog1.FileName, IO.FileMode.Open)

            opFile.Seek(0, IO.SeekOrigin.Begin)
            bi() = opFile.Read()←バイト型配列に読み込ませる方法がよくわからないんです><
        End IF

お忙しい中本当ごめんなさい・・

>今回の場合は、最初からByte配列のまま読み込んで、それをBitConverterで変換した方が楽でしょう。


魔界の仮面弁士  2004-09-24 04:01:46  No: 116426

> 「BASE64」での変換処理は全くしたくないんです
なるほど、了解しました。(ところで、BASE64って何か御存知ですか?)

> Dim opFile As New System.IO.FileStream(OpenFileDialog1.FileName, IO.FileMode.Open)
上記は例えば、
  Dim opFile As System.IO.FileStream
  opFile = New System.IO.FileStream(OpenFileDialog1.FileName, IO.FileMode.Open)
とか、あるいは、
  Dim opFile As System.IO.FileStream = New System.IO.FileStream(OpenFileDialog1.FileName, IO.FileMode.Open)
などとも書けます。
「Dim 変数名 As New 〜」の構文は、これらを省略した表記方法と言えます。

> にあるように  New  ってどういう意味を持つのでしょうか??
クラスを利用するには、多くの場合、New を使ってオブジェクトを作成する必要があるのです。
(この事を、「インスタンスを割り当てる」という言い方をする場合もあります)

そして New とは、データ型の新しいインスタンスを作成するためのキーワードです。

……これだと分かりにくいかも知れませんので、別の言い方をしてみます。

クラスと、そのインスタンス(オブジェクト)とを比較した場合、クラスは「設計図」、
そしてインスタンスは「設計図によって作られたモノ」と喩えられることがあります。

たとえば、「Form」というクラスは御存知ですよね。この Form を使って、
   Dim F As New Form()
   F.Show()
のようなコードを(ボタンのClickイベントなどに)書いてみたとします。
そうすると、空のフォームを表示する事ができるはずです。

しかしここで、New を記述するのをやめて、
   Dim F As New Form()
   F.Show()
と書いた場合は、
   "オブジェクト参照がオブジェクト インスタンスに設定されていません。"
というエラー (NullReferenceException例外) になってしまいます。
これは何故かわかりますでしょうか?

単に Form 型の変数を宣言しただけでは、「フォームの設計図」が宣言されただけなので、
この変数 F の実態は、まだ存在していない状態(Nothing) のままとなります。

フォームがまだ作られていないのに、それを表示(Show)させようとすると、エラーになります。
画面に表示したいのなら、Formという設計図を元に、実際のフォームを作成する
必要があるというわけです。

そして、この時に使われるのが、New というキーワードです。
これを使えば、フォームを新規に作成してあげる事ができます。

# この New というキーワードは、今回使っていた OpenFileDialog1 などでも利用されています。
# 普段は、開発環境が自動生成してくれているので、気が付きにくいですが、コード中の
# 『 Windows フォーム デザイナで生成されたコード 』という部分を開いてみると、
# OpenFileDialog などの各種コントロールを New している箇所を見る事ができます。

なお、クラスによっては、作成時に幾つかの付加情報を必要とするものもあります。
そうしたクラスの場合は、New する時の引数に、それらの情報を渡す事になります。
(そして System.IO.FileStream も、New 時に引数を必要とするクラスです)

———さて、話を FileStream クラスに戻してみます。

ファイルを読み込むために、FileStream クラスを使おうとしても、
  Dim opFile As System.IO.FileStream
のように変数を宣言しただけでは、opFile は空っぽ(Nothing)の状態のままなので、
ファイルの読み込みは行えません。

実際にファイルを操作したいのであれば、『New』を使って、この opFile 変数に、
「何というファイルを、どのような形式で扱うのか」という情報を作成し、
それを、opFile に格納してあげる必要があるというわけです。

# New とはこのような働きをしているわけですが…こんな感じの説明でわかりますか?(^^;)


魔界の仮面弁士  2004-09-24 04:41:14  No: 116427

コードの一例として、具体的なサンプルを書いてみますね。

# 本当は、もう少し早くサンプルを書きたかったのですが、モバイル端末に
# .NETを入れてなかったので、今まで具体例を書けませんでした…。
## 先ほど、1週間の出張から帰って来れたので、ようやくサンプルが書けます。(^_^;)

> bi() = opFile.Read()←バイト型配列に読み込ませる方法がよくわからないんです><
バイト配列に読み込ませるには、幾つかの方法がありますが、
たとえば、以下のような書き方をする事ができます。(エラー処理は省略しています)

====================
'この変数に、ファイルのバイナリを格納します。
Dim Buffer() As Byte

'読み取るファイル名の指定です。ここでは直接指定していますが、
'OpenFileDialog を使って指定させても、もちろん OK です。
Dim FilePath As String = "C:\TEST.TXT"

'ファイルの読み込みを行う部分です。
'第2引数以降は、必要に応じて変更してみて下さい。
Dim DataFile As New System.IO.FileStream(FilePath, IO.FileMode.Open)

'データファイルのサイズを調べています。
Dim FileSize As Integer = CInt(DataFile.Length)
If FileSize = 0 Then
    '空のファイルであれば、データを読み込む必要も無いので、
    'ファイルは読まず、テキストボックスを空にしています。
    Me.TextBox1.Clear()
Else
    'データがあった場合、データサイズに合わせて配列サイズを決定します。
    '今回は、データ量と同サイズの配列を用意しています。
    ReDim Buffer(FileSize - 1)

    '用意した配列にデータを読み込みます。
    '下記では、「Buffer(0)〜Buffer(FileSize-1)」に対して読み込ませています。
    DataFile.Read(Buffer, 0, FileSize)    '★★

    '受け取った配列を、BitConverterクラスを利用して、
    'TextBoxに表示させます。
    Me.TextBox1.Text = System.BitConverter.ToString(Buffer)
End If

'開いたファイルは、最後に必ず閉じる必要があります。
DataFile.Close()
====================

なお、上記の手法だと、一度に全データを読み込ませているため、大きなファイルの場合は、
負荷が大きくなってしまいます。もし、大きめなファイルを読み込ませる必要があるならば、
一度に全部を読み込むのではなく、最初は先頭部分(たとえば、先頭16KB分)のデータだけを
読み込ませるようにしておき、必要に応じて、次の部分(〜32KBまでの部分)のデータを
読み込むようにすれば、対処できるかと思います。


魔界の仮面弁士  2004-09-24 08:59:09  No: 116428

別解。
FileStreamクラスのRead()メソッドの替わりに、
BinaryReaderクラスのReadBytes()メソッドを呼び出しています。

====================
Dim FilePath As String = "C:\TEST.TXT"
Dim DataFile As New System.IO.FileInfo(FilePath)
If DataFile.Exists AndAlso DataFile.Length > 0 Then
    With New System.IO.BinaryReader(DataFile.OpenRead())
        Me.TextBox1.Text = BitConverter.ToString(.ReadBytes(CInt(DataFile.Length)))
        .Close()
    End With
Else
    Me.TextBox1.Clear()
End If
====================


π  2004-09-24 10:26:19  No: 116429

魔界の仮面弁士さん、いつもいつも本当にありがとうございます!!!そして出張お疲れ様でした(>_<")レスが遅れてごめんなさい、バイトをしているもので帰りがこの時間帯になってしまうんです。。

>(ところで、BASE64って何か御存知ですか?)
BASE64は学校で習ったつもりだったんですが・・。2の6乗の64通りで文字を表すとかじゃなかったでしたっけ?

>クラスは「設計図」、そしてインスタンスは「設計図によって作られたモノ」と喩えられることがあります。
 >この New というキーワードは、今回使っていた OpenFileDialog1 などでも利用されています。

大変わかりやすかったです<(_ _*)> そしてとても勉強になりました!!Newとすることで新しく作っているのですね!その裏づけとしてOpenFileDialog1.など、ドット以下に指定できるものがインスタンスということですよね。あぁなるほど、だからOpenFileDialog1もどこかで宣言されているのですね!!

>  Dim F As New Form()
>   F.Show()
大変わかりやすいですo(*▼▼*)o あぁこんなこともできるのかぁと関心させられました!

>           '用意した配列にデータを読み込みます。
>            '下記では、「Buffer(0)〜Buffer(FileSize-1)」に対して読み込ませています。
>            DataFile.Read(Buffer, 0, FileSize)    '★★
取得したバイトが10バイトだとして、上記でFileSize-1としているのは、バイト配列Bufferが0番地から始まるからですよね?この一文でバイト型配列に読み込めるんですね><!!すごい><!!

>       '開いたファイルは、最後に必ず閉じる必要があります。
>       DataFile.Close()
もし閉じないと、データがおかしくなったりしてしまうのでしょうか?ちょっと怖いです。でも必ず閉じるようにします!!

>もし、大きめなファイルを読み込ませる必要があるならば、一度に全部を読み込むのではなく、最初は先頭部分(たとえば、先頭16KB分)のデータだけを読み込ませるようにしておき、必要に応じて、次の部分(〜32KBまでの部分)のデータを読み込むようにすれば、対処できるかと思います。

16KBで分けるのには何か特別な意味はありますか?例えば、100KBのデータがあったとして、始めに50KB分よんで、次に読み込むときは、DataFile.Read(Buffer,49,100)ということですよね?

やっと解決できました^^!!大変感謝しています!!


π  2004-09-24 12:38:14  No: 116430

>Stringの場合は、文字コードのエンコーディングの指定の関係上、このメソッドではなく、System.Text.Encodingを使って、文字列→Byte()変換を行うことになります。

こんばんは。あらかじめ決まった文字列をバイト配列に入れる場合は、バイト型にしなくてはいけないと思うのですが、

        Dim TestChara As String = "あいうえおこれはてすとです"
        Dim TestBytes(TestChara.Length) As Byte

として、
       TestBytes = System.Text.Encoding.???この後がわからないのですが・・(いろいろ試しても下線がついてしまいます><)もしくはNewのように新しく何かを作る必要があるのでしょうか。。

再三にわたりすみませんです><


魔界の仮面弁士  2004-09-24 14:04:46  No: 116431

> BASE64は学校で習ったつもりだったんですが・・。
私の学科ではそうした授業が無かったので、ちょっと羨ましいです。(^^;

> 2の6乗の64通りで文字を表すとかじゃなかったでしたっけ?
「文字を表す」ではなく、「文字で表す」でしょう。

> バイト配列Bufferが0番地から始まるからですよね?
ですます。そういう事です。

> もし閉じないと、データがおかしくなったりしてしまうのでしょうか?
たとえば、ロックの問題などがあります。

ファイルを開いている間は、他のユーザーが内容を変更できないようにする事ができます。
(他のアプリがそのファイルに対してデータを書きこめないよう、ファイルがロックされます)

この時、もしも Close するのを忘れていると、そのファイルはいつまでもロックされたままに
なってしまいますので、他のアプリケーションが、いつまでたってもそのファイルを
使えないなってしまうという事態が発生します。

一応の保護措置として、(処理が終了したり、アプリが閉じられたりなどして)
使用していた変数が Nothing 状態になれば、.NETの『ガベージコレクト』が
行われたタイミングで、自動的に Close 処理が行われるようにはなっています。

しかし、だからといって、ガベージコレクトされるまで放置するわけにもいきませんよね。
(その間、他のアプリがそのファイルを使えないのですから)

そして、解放処理が必要なのは、FileStreamクラスだけではありません。
ファイルに限らず、Windowsの資源(リソース)の多くは、解放処理を必要とします。

具体的には、 Form や Image や Font などが、解放が必要なクラスとなっています。
これらのクラスは、使用後に Dispose メソッドでオブジェクトを破棄してやらないと、
利用していたメモリの一部がシステムに返還されない可能性があるのです。
(ちなみに、Disposeが必要なクラスには、IDisposableインターフェイスが実装されています)

> 16KBで分けるのには何か特別な意味はありますか?
バイト数は適当なので、32KBでも20KBでも構いません。

ただ、Win9X系 OS では、TextBox に 64KB までの制限がありますので、
それより小さい値として、16KBという値を選んだだけの事です。

> 例えば、100KBのデータがあったとして、始めに50KB分よんで、次に読み込むときは、DataFile.Read(Buffer,49,100)ということですよね?
……違いますよ。それでは、49バイト目〜148バイト目に読み込む事になってしまいます。

100KBという事は、102,400バイトという事なので、書き換えるなら、
  最初の100KB分: DataFile.Read(Buffer, 0, 102400)
    次の100KB分: DataFile.Read(Buffer, 0, 102400)
といった感じになります。2回目の呼び出しが、
    DataFile.Read(Buffer, 102400, 102400)
だと、意味が異なってくるので、注意してください。

Readメソッドで指定する位置と長さは、ファイル内の位置を示しているのではなく、
受け取る配列側の位置を示している点に注意してください。

例えば、元データが 16バイトあったとして、
   0バイト目: &H00
   1バイト目: &H01
   2バイト目: &H02
      :
      :
  14バイト目: &H0E
  15バイト目: &H0F
のようになっていたとします。

この時、
  Dim Buffer(8) As Byte
  DataFile.Read(Buffer, 0, 3)
のようなコードを実行すれば、配列の内容は、
  Buffer(0) = &H00
  Buffer(1) = &H01
  Buffer(2) = &H02
  Buffer(3) = 変化無し
  Buffer(4) = 変化無し
  Buffer(5) = 変化無し
  Buffer(6) = 変化無し
  Buffer(7) = 変化無し
  Buffer(8) = 変化無し
のようになります。

そしてその後で、さらに、
  DataFile.Read(Buffer, 5, 3)
と呼び出すと、配列の中身は、
  Buffer(0) = &H00(変化無し)
  Buffer(1) = &H01(変化無し)
  Buffer(2) = &H02(変化無し)
  Buffer(3) = 変化無し
  Buffer(4) = 変化無し
  Buffer(5) = &H03
  Buffer(6) = &H04
  Buffer(7) = &H05
  Buffer(8) = 変化無し
のようになります。


魔界の仮面弁士  2004-09-24 14:47:54  No: 116432

> π 2004/09/24(金) 03:38:14
# 夜更かしせず、早く寝ましょう。(人の事は言えない……)

えぇと、文字列からバイト配列への変換についてですね。

.NETの世界では、文字列は「UTF-8」という形式で管理されています。
これは、普段目にしている「Shift_JIS」とは異なる形式です。

例えば、 "ABC" という文字列があった場合、バイナリとしては、
      UTF-8 : 41 42 43  (3バイト)
  Shift_JIS : 41 42 43  (3バイト)
のように、同じバイナリなのですが、"αβγ" の場合は、
      UTF-8 : CE B1 CE B2 CE B3  (6バイト)
  Shift_JIS : 83 BF 83 C0 83 C1  (6バイト)
のように、バイナリが異なってきますし、全角の "ABC" の場合は、
      UTF-8 : EF BC A1 EF BC A2 EF BC A3  (9バイト)
  Shift_JIS : 82 60 82 61 82 62  (6バイト)
と、バイト数まで違ってきてしまうのです。

# しかもこれらは、VBのAscW関数で変換されるコードとは、
# 別のエンコードだったりもします。

文字列のエンコードには、他にもいろいろな種類がありますので、
文字列をバイナリに変換する場合には、どのエンコードを使って
変換するのかが、非常に重要になってくるわけです。

そして、この変換を担うのが、System.Text.Encodingクラスというわけです。

Dim BaseText As String = "あいうえお"
Dim A(), B() As Byte
A = System.Text.Encoding.UTF8.GetBytes(BaseText)
B = System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(BaseText)

この場合、どちらも元データは「あいうえお」の5文字ですが、
A にはUTF-8形式、B にはShift_JIS形式にて変換が行われます。

> Newのように新しく何かを作る必要があるのでしょうか。。
New を使うのであれば、
    Dim UTF8 As System.Text.Encoding
    UTF8 = New System.Text.UTF8Encoding()
    A = UTF8.GetBytes(BaseText)
のように書く事もできます。

# 上記のUTF8Encodingクラスは、Encodingクラスから派生(Inherits)されているため、
# UTF8Encodingクラスのインスタンスは、Encodingクラスの変数に格納する事ができます。

あるいは、より短く、
    Dim UTF8 As New System.Text.UTF8Encoding()
    A = UTF8.GetBytes(BaseText)
などと書く事もできます。

ただ、GetBytesメソッドは静的メソッドですので、Newせずに、
  A = System.Text.Encoding.UTF8.GetBytes(BaseText)
と書く事も可能となっています。

なお、「静的メソッド」という用語については、下記を参照してみてください。
http://www.atmarkit.co.jp/fdotnet/basics/oop03/oop03_04.html


魔界の仮面弁士  2004-09-24 14:52:35  No: 116433

》 魔界の仮面弁士 2004/09/23(木) 19:01:46
あう。記述ミス。。。

> しかしここで、New を記述するのをやめて、
>    Dim F As New Form()
>    F.Show()
> と書いた場合は、
>    "オブジェクト参照がオブジェクト インスタンスに設定されていません。"
> というエラー (NullReferenceException例外) になってしまいます。

これではエラーになりませんね。失礼しました。
    Dim F As New Form()
ではなく、
    Dim F As Form
と書くつもりでした。m(_ _)m 読み変えてください。


π  2004-09-25 02:02:58  No: 116434

こんにちは!学校からです!返信ありがとうございます!!昨日は朝まで書いていたんですが、夜更かしせず寝なさいとの文字をみて素直に寝させてもらいました^^vプログラムを書くとひとつ解決したと思ったらまたひとつ壁にぶつかるんだなって最近よく思います^^;疑問に思ったことを書かせてもらいます><

>たとえば、ロックの問題などがあります。
なるほど!!だからファイルを読んでいるときはほかのプロセスで使用していますなどとメッセージが出てしまったんですね!!納得です!

>Windowsの資源(リソース)の多くは、解放処理を必要とします。
ハイ!これからは開けたら閉じるの習慣をつけます^^アドバイスありがとうございます。

>100KBという事は、102,400バイトという事なので、書き換えるなら、
> 最初の100KB分: DataFile.Read(Buffer, 0, 102400)
> 次の100KB分: DataFile.Read(Buffer, 0, 102400)
このコードをみて自分の勘違いに気がつきました><!!この場合は、Bufferの0番地から102400番地に読み込まれて、次の100KB分はBufferに新たに付けたされるのじゃなくて、同じ0番地から102400番地に上書きされるということですね!
慣れるまでは難しいですねっ!!がんばります!

>Readメソッドで指定する位置と長さは、ファイル内の位置を示しているのではなく、受け取る配列側の位置を示している点に注意してください。
はい!では逆に言うと、ファイルの一部分だけを配列にいれるということはできないのでしょうか。。

>例えば、元データが 16バイトあったとして、
>   0バイト目: &H00
>   1バイト目: &H01
>   2バイト目: &H02
>      :
>      :
>  14バイト目: &H0E
>  15バイト目: &H0F
>のようになっていたとします。
大変わかりやすかったです><!魔界の仮面弁士さんは相当極めていらっしゃる方なんですね!!

で、この時なんですけど、元データ3バイト目から4バイト目(&H03と&H04)をBuffer(1)とBuffer(2)にそれぞれいれるといった処理は可能なんでしょうか?調べましたがここまで複雑なのは本には載ってなかったんです><
  DataFile.Read(Buffer, 0, 3)
Bufferの開始位置を指定したり、データの開始位置を指定したり・・んっ、、この辺のテクニックを是非教えていただきたいです><

>  Dim Buffer(8) As Byte
>  DataFile.Read(Buffer, 0, 3)
>のようなコードを実行すれば、配列の内容は、
>  Buffer(0) = &H00
>  Buffer(1) = &H01
>  Buffer(2) = &H02
>  Buffer(3) = 変化無し
>       ・
>  ・
>のようになります。
わかりやすすぎます><魔界の仮面弁士さんに教わった人は、なんというかハッキリ理解してるんだろうなぁと思いました。
だから、
>あう。記述ミス。。。
のところは、言葉だけでわかってましたから大丈夫です!わざわざありがとうございます!!!

>.NETの世界では、文字列は「UTF-8」という形式で管理されています。文字列のエンコードには、他にもいろいろな種類がありますので、文字列をバイナリに変換する場合には、どのエンコードを使って変換するのかが、非常に重要になってくるわけです。

ここで疑問に思うことがあります!.NETの世界では「UTF-8」という形式で管理されてるとのことですが、
ファイル(sample.txt)の中身:”   ft”

Dim FileData as String = "   ft"
Dim Buffer as Byte
Buffer = System.Text.Encoding.UTF8.GetBytes(FileData)
として
TextBox1.Text = System.BitConverter.ToString(FileData)
とすると・・
20-20-20-18-66-74と表示されるんですが、
sample.txtをDialogBoxで指定して読み込み、
TextBox1.Text = System.BitConverter.ToString(SAMPLE_data)
とすると、
00-00-00-18-66-74と、今度は違う値が出力されるんです・・!

エンコードが違うことを意味すると思うのですが・・ちょっとよくわからないんです><

長々と申し訳ありませんです!!


π  2004-09-25 03:07:37  No: 116435

読込み位置はBaseStream.Seek()でしょうか。。ためしてみます!!


魔界の仮面弁士  2004-09-25 05:07:48  No: 116436

> では逆に言うと、ファイルの一部分だけを配列にいれるということはできないのでしょうか。。
もちろん、可能ですよ。

FileStreamクラスでは、現在、どの位置まで読み込まれているのかという
カーソル情報を内部的に保持しています。
そしてこのカーソル位置は、Position プロパティで参照/変更が可能です。

   Dim Buffer(15) As Byte
   Dim FileReader As New System.IO.FileStream("C:\TEST.TXT", IO.FileMode.Open)

   '&H1F 〜 &H23 までの 5バイト分を、
   'Buffer(3)〜Buffer(7) の位置に読み込ませる。
   FileReader.Position = &H1F
   FileReader.Read(Buffer, 3, 5)

   'TextBoxに表示させて、配列の内容を確認。
   Me.TextBox1.Text = System.BitConverter.ToString(Buffer)

   FileReader.Close()

> 魔界の仮面弁士さんは相当極めていらっしゃる方なんですね!!
一応、Visual Basic の「MVP」として認定されていたりします。
http://mvp.support.microsoft.com/default.aspx?scid=fh;en-us;mvpaward&style=toc

> ファイル(sample.txt)の中身:”   ft”
Unicode で言えば、
  1文字目: U+0020  "SPACE"
  2文字目: U+0020  "SPACE"
  3文字目: U+0020  "SPACE"
  4文字目: U+0018  <CONTROL> (CAN)
  5文字目: U+0066  "LATIN SMALL LETTER F"
  6文字目: U+0074  "LATIN SMALL LETTER T"
というデータの並びになりますね。

これを UTF-8 でエンコードすれば、「20 20 20 18 66 74」となりますので、
> 20-20-20-18-66-74
これは正しく表示されている事になります。

> TextBox1.Text = System.BitConverter.ToString(SAMPLE_data)
この『SAMPLE_data』というのは、どのようにして作成されたのでしょうか?
この部分が分からないため、何とも回答しにくいのですが、少なくとも当方では、

 With New System.IO.BinaryReader(New System.IO.FileStream("C:\TEST.TXT", IO.FileMode.Open))
     Me.TextBox1.Text = System.BitConverter.ToString(.ReadBytes(6))
     .Close()
 End With

というコードで、『20-20-20-18-66-74』という結果を得られましたよ。

> 読込み位置はBaseStream.Seek()でしょうか。。ためしてみます!!
それでも OK です。
先に、Position プロパティという物を紹介しましたが、Seekメソッドでも移動が可能です。

ちなみに、(BinaryReaderクラスの)BaseStream プロパティは、ヘルプにもあるように、
基となるストリームを返してくれる仕様ですので、

    Dim myFileStream As New System.IO.FileStream("C:\TEST.TXT", IO.FileMode.Open)
    Dim myBinaryReader As New System.IO.BinaryReader(myFileStream)

    If myBinaryReader.BaseStream Is myFileStream Then
         MessageBox.Show("両者は、同じオブジェクトです。")
    Else
         MessageBox.Show("両者は、異なるオブジェクトです。")
    End If

「myBinaryReader.BaseStream.Seek(〜)」というコードというのは、
「myFileStream.Seek(〜)」と全く同じ意味と言う事になります。


魔界の仮面弁士  2004-09-25 06:12:03  No: 116437

# 一箇所ツッコミ。

[2004/09/24(金) 17:02:58]
>> 最初の100KB分: DataFile.Read(Buffer, 0, 102400)
>> 次の100KB分: DataFile.Read(Buffer, 0, 102400)
> この場合は、Bufferの0番地から102400番地に読み込まれて、次の100KB分はBufferに新たに付けたされるのじゃなくて、同じ0番地から102400番地に上書きされるということですね!

0〜102400 ではなく、0〜102399 ですよね。


π  2004-09-25 06:32:25  No: 116438

>   '&H1F 〜 &H23 までの 5バイト分を、
>   'Buffer(3)〜Buffer(7) の位置に読み込ませる。
>   FileReader.Position = &H1F
>   FileReader.Read(Buffer, 3, 5)

こんにちは、seekはちょっと使い方がわからなかったのですが、Positionはわかりました!!Positionで何バイト目から読み込むとかもできるんですね><感動しました。

>一応、Visual Basic の「MVP」として認定されていたりします。
えっ・・・マイクロソフト認定のMVPって・・とてつもなくすごい人なんじゃないですか><;

>この『SAMPLE_data』というのは、どのようにして作成されたのでしょうか?
SAMPLE_dataは、
Dim DataFile As New System.IO.FileStream("c:\sample.txt", IO.FileMode.Open)
で読み込んで出力したんですけど、やはりTextbox1には「00-00-00-18-66-74」とスペースの部分だけ違う値が出てしまうんです・・。テキストの内容を開いてコピーペーストして
Dim FileData as String = "   ft"
のようにした時点でスペースの文字コードが変わってしまうということなんでしょうか。。
テキストで上書きしたりするとスペースの文字コードが20となってしまいます。

http://jp.y42.briefcase.yahoo.co.jp/bc/bapexslyme/lst?&.dir=/public&.src=bc&.view=l&.last=1
これがSample.txtです。バイナリエディタ【Stirlingというソフト】で表示していたものを切り取って保存しました。

それにしても魔界の仮面弁士さんって雲の上の人って感じです。職人というか仙人というか・・師匠とよばせてください^^vいつかプログラムを作って公開できるときは、SpecialThanxのところに絶対書きます^^
「ファイルをバイナリで読むには??」はおかげさまで解決することができました!!!長くなってしまうのでまた違う質問は新たにスレッドを立たせてください><


魔界の仮面弁士  2004-09-25 08:37:04  No: 116439

> 「00-00-00-18-66-74」とスペースの部分だけ違う値が出てしまうんです・・。
アップロードされた Sample.txt ファイルを見てみましたが、
本当に「00」が書かれていましたよ。Stirlingで確認してみてください。
なので、その表記自体は間違ってはいないはずです。

> コピーペーストして
&H00 は、C言語における「文字列の終端」を意味しますので、
文字列のコピー&ペーストでは、正しくコピーされないでしょう。


π+  2004-09-25 22:20:50  No: 116440

魔界の仮面弁士さん、どうもありがとうございました><深くお礼申し上げます><
Stirlingで確認しました。00は文字列の終端を意味するんですね!またひとつ勉強になりました!!


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

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






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