連載
プロフェッショナルVB.NETプログラミング
第8回 ファイル入出力(後編)
(株)ピーデー
川俣 晶
2002/06/08
|
|
テキスト・ファイルの書き込み位置
VB 6では、Seek関数により、書き込み中のファイルの先頭からの位置を知ることができる。また、Seekステートメントでこの位置を変更することができる。以下はそれを示すサンプル・プログラムである。
1: Private Sub Form_Load()
2: Dim fileno As Integer
3: fileno = FreeFile
4:
5: Open "c:\test.txt" For Output As #fileno
6: Print #fileno, "亜意宇";
7: Dim p As Long
8: p = Seek(1)
9: Print #fileno, "えお"
10: Seek #1, p
11: Print #fileno, "得御"
12: Close #fileno
13:
14: Dim s As String
15: Open "c:\test.txt" For Input As #fileno
16: While Not EOF(fileno)
17: Line Input #fileno, s
18: Debug.Print s
19: Wend
20: Close #fileno
21: Debug.Print p
22: End Sub |
|
Seek関数とSeekステートメントを使用したVB 6のサンプル・プログラム5 |
これを実行すると以下のようになる。
これと同等の機能を持つVB.NETのプログラムは以下のようになる。
1: Public Class Form1
2: Inherits System.Windows.Forms.Form
3:
4: #Region " Windows フォーム デザイナで生成されたコード "
5:
6: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
7: Dim fileno As Integer
8: fileno = FreeFile()
9:
10: FileOpen(fileno, "c:\test.txt", OpenMode.Output)
11: Print(fileno, "亜意宇")
12: Dim p As Long
13: p = Seek(1)
14: Print(fileno, "えお")
15: Seek(1, p)
16: PrintLine(fileno, "得御")
17: FileClose(fileno)
18:
19: Dim s As String
20: FileOpen(fileno, "c:\test.txt", OpenMode.Input)
21: While Not EOF(fileno)
22: s = LineInput(fileno)
23: Trace.WriteLine(s)
24: End While
25: FileClose(fileno)
26: Trace.WriteLine(p)
27: End Sub
28: End Class |
|
サンプル・プログラム5をVB.NETで書き換えたサンプル・プログラム6 |
これを実行すると以下のようになる。
見てのとおり、ほとんど同じ機能を持つSeek関数が提供されているので、VB.NETへの移行は難しくない。だが、クラス・ライブラリを使用するように書き換える場合はどうだろうか? 以下は同等の機能をクラス・ライブラリのStreamWriterクラスを使用して記述してみた例である。
1: Imports System.IO
2:
3: Public Class Form1
4: Inherits System.Windows.Forms.Form
5:
6: #Region " Windows フォーム デザイナで生成されたコード "
7:
8: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
9: Dim writer As StreamWriter, reader As StreamReader
10: writer = New StreamWriter("c:\test.txt")
11: writer.Write("亜意宇")
12: Dim p As Long
13: writer.Flush()
14: p = writer.BaseStream.Position
15: writer.Write("えお")
16: writer.Flush()
17: writer.BaseStream.Position = p
18: writer.WriteLine("得御")
19: writer.Close()
20:
21: reader = New StreamReader("c:\test.txt")
22: Do
23: Dim s As String
24: s = reader.ReadLine()
25: If s = Nothing Then Exit Do
26: Trace.WriteLine(s)
27: Loop
28: reader.Close()
29: Trace.WriteLine(p)
30: End Sub
31: End Class |
|
サンプル・プログラム6を、クラス・ライブラリを使用して書き換えたVB.NETのサンプル・プログラム7 |
これを実行すると以下のようになる。
このプログラムにはいくつか、初めてお目に掛かるキーワードがある。まずFlushメソッドはまだ書き込まれていないデータを書き込む働きがある。パフォーマンスを向上させるために、書き込みデータのバッファリングが行われているため、確実に書き込むためには、このメソッドを呼び出す必要がある。ただし、ファイルを閉じるときには確実に書き込まれるため、通常は間違いなく閉じるようにすれば問題ない。問題が起きるのは、閉じる前に書き込み位置を変更したりする場合である。
次に、BaseStreamというプロパティは、実際に入出力を行うオブジェクトを参照する機能を持つ。そして、Positionプロパティは、書き込み位置を設定/取得できるプロパティである。つまり、PositionプロパティはVBのSeek関数、Seekステートメントとほぼ同じ役割を持つものである。バッファリングはStreamWriterクラスで、位置の管理はBaseStreamプロパティで参照されるクラスで行われるため、Positionプロパティを読み書きする場合は、その前にFlushメソッドを呼んでバッファを書き込んでおく必要がある。
さて、出力されている最後の数値を見ていただきたい。“7”だったはずの数値が、クラス・ライブラリを使うと“9”に化けている。値が違うことには2つの理由がある。1つは、1文字の占めるバイト数がシフトJISとUTF-8では違うこと。漢字や「かな」は3bytesを要するため、シフトJISよりも多くの容量を占有する。もう1つの理由は、位置を数える起点となる位置が違うためだ。VBではファイルの先頭のバイトは1とするが、クラス・ライブラリでは0としている。この違いが、値が1つずれる原因となっている。
文字列サイズの変化
シフトJISに慣れたプログラマー向けに1つ余談を書こう。以下のようなソースがあるとする。
1: Imports System.IO
2:
3: Public Class Form1
4: Inherits System.Windows.Forms.Form
5:
6: #Region " Windows フォーム デザイナで生成されたコード "
7:
8: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
9: Dim writer As StreamWriter, reader As StreamReader
10: writer = New StreamWriter("c:\test.txt")
11: writer.Write("亜意宇")
12: Dim p As Long
13: writer.Flush()
14: p = writer.BaseStream.Position
15: writer.Write("得御可")
16: writer.Flush()
17: writer.BaseStream.Position = p
18: writer.Write("ΘΛ¶")
19: writer.Close()
20:
21: reader = New StreamReader("c:\test.txt")
22: Do
23: Dim s As String
24: s = reader.ReadLine()
25: If s = Nothing Then Exit Do
26: Trace.WriteLine(s)
27: Loop
28: reader.Close()
29: Trace.WriteLine(p)
30: End Sub
31: End Class |
|
シフトJISとUTF-8の違いを示すVB.NETのサンプル・プログラム8 |
これを実行すると以下のようになる。
このプログラムでは、文字列「得御可」を「ΘΛ」で上書きしている。にもかかわらず、「得御」は消えたのに「可」は残っていて、出力されてしまっている。その理由は何だろうか?
これは、UTF-8で表現したとき、「得御可」はいずれも1文字3bytesで表現されるのに対して、「ΘΛ」は1文字2bytesで表現されているためだ。つまり、シフトJISで2bytesだった文字がすべて3bytesになるという前提を置くことはできない。従ってこのようにして、すでに書き込んだ文字を上書きする場合は、同じ文字数を書いても上書きになるとは限らない。十分に注意していただきたい。
次回予告
次回はオブジェクト関連の機能を取り上げたいと考えている。
Insider.NET 記事ランキング
本日
月間