DOBON.NET DOBON.NETプログラミング掲示板過去ログ

任意の行に上書き処理する方法

環境/言語:[VB.NET Compact Framework 2.0]
分類:[.NET]

開発環境:WindowsXP[HOME]
開発環境:VB.NET Compact Framework 2.0
使用環境:PDA

最大250KBほどのファイルに対して、上書き処理を行いたいと思っています。
上書き処理を行う行は事前に別のindexファイルにて取得しております。
また、その行の内容は別の変数にて持っている状態です。
以下のように仕組みとしては一部を書き換える仕様ですが、それは難しそうなので、
削除後、追記という形でいきたいと思っています。

書き込む前の内容「XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX」
書き込みたい内容「XXXXXXXXXXXXXXXXXXXXXXXXXYYYYYYXXXXXXXXXXXXXXXXXXXXXXXX」
                                           ~~~~~~

現在下記のようなソースで処理を行おうとしています。
ですが、バイト変換でエラーが出ます。
エラー内容は「引数'Prompt'は型'String'に変換出来ません。」
「strByte = System.Text.Encoding.Unicode.GetBytes(aobjBuff)」と変更しても駄目でした。
同じエラーメッセージが表示されます。
まとはずれなことを書いているかもしれませんが、
それも含めてレス頂けたら幸いです。

'// alngGyo  = 書き込む行
'// astrBuff = 書き込む内容
Private Function Dat_Write(ByVal alngGyo As Long, ByRef astrBuff As String) As Boolean
    Dim fs As System.IO.FileStream
    Dim strByte() As Byte

    '// ファイルオープン
    fs = New System.IO.FileStream("ファイル名", IO.FileMode.Open, IO.FileAccess.Write)

    '// Seek処理
    fs.Seek(alngGyo, System.IO.SeekOrigin.Begin)

    '// バイト変換
    strByte = System.Text.Encoding.GetEncoding("shift-jis").GetBytes(CType(astrBuff, Byte))

    '// 書き込み
    fs.Write(strByte, 0, strByte.Length)

end Function
とにかく、使おうとしているクラスやメソッドについてMSDNを読んで理解してください。
そのあと一つ一つの命令の表現が正しいことを確認してから、それらの組み合わせで期待していることが実現できるかを検証してください。
コードを見る限り「そのエラーの原因は」とか「ここをこうすれば」という返答段階ではないようにお見受けします。

とりあえず基礎以外では、
・Longである必要はあるの? ※VB6の残骸?
・行番号という人間の決めた値をそのままSeekに指定して動きますか?
というところです。

あとコードにはないPromptやaobjBuffというものが出てきます。
説明が一切ないのに「〜にしてもダメでした」と言われてもどうしようもありません。
正確に、そして伝えなければいけないことに漏れが無いように書いてください。
■No21928に返信(まどかさんの記事)
> ・Longである必要はあるの? ※VB6の残骸?
Dat_Write の引数として使うのが適正かどうかという論議は別として、
FileStream.Seek を使うのであれば、その Offset 引数は Long なので、
最終的には Long 型になるかと思います。


■No21926に返信(向井さんの記事)
> '// astrBuff = 書き込む内容
この引数を「ByRef」にされているのは、何か理由があるのでしょうか?
見た感じでは、ByVal で十分だと思いますけれども…。


> Private Function Dat_Write(ByVal alngGyo As Long, ByRef astrBuff As String) As Boolean
ここは、Sub にした方が良いような気がします。
戻り値が設定されていないようですし。(常に False を返している)


> fs = New System.IO.FileStream("ファイル名", IO.FileMode.Open, IO.FileAccess.Write)

バイナリの書き換えであれば、FileStream に加えて、
BinaryReader / BinaryWriter を併用すると、コーディングが楽になりますよ。

> '// Seek処理
> fs.Seek(alngGyo, System.IO.SeekOrigin.Begin)
既にまどかさんが指摘されていますが、この部分がちょっと怪しいです。
「行数」と「バイト位置」は異なる値ですよね。

> strByte = System.Text.Encoding.GetEncoding("shift-jis").GetBytes(CType(astrBuff, Byte))
ここ、いろいろと間違っています。
そもそも、Byte 型を .GetBytes メソッドに渡そうとしている点が間違っています。

Encoding クラスには、『.GetBytes(Byte)』なメソッド定義はありません。
『.GetBytes(Byte[])』もありません。
『.GetBytes(String)』なメソッドならばありますけれども。


また、もしも .GetBytes(Byte) が用意されていたと仮定しても、
 CType(astrBuff, Byte)
という、「文字列からバイト型への変換」という処理そのものがおかしいです。
String → Byte への単純な変換となれば、
 astrBuff = "123"
 Dim x As Byte = CByte(astrBuff) '数値 123 になる
とは書けますが、そういう意味で書いたわけでも無いですよね。

本当にやりたかったのは、下記のような物では無いでしょうか。
 strByte = System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(astrBuff)


> '// 書き込み
> fs.Write(strByte, 0, strByte.Length)
この方法でも良いですが、BinaryWriter 経由で Write すると、
Encoding.GetBytes 無しで元の文字列(astrBuff) を直接渡せるので、
処理が楽になるかと思います。


> end Function
その前に、FileStream の解放処理を記述しておきましょう。
お二方返信ありがとうございます。動くようにはなりました。
知識的な部分では解決はしていませんが、
仕様通りの動作はしているということで解決済みにさせていただきます。
数日前からVB6から.NETへ作業が移って右往左往しておりました。
エラーの原因は当初からデバックが出来ないため、Msgboxで変数を表示させていたときにByte変数の表示でエラーになっていたためでした。
調べた結果、「.NET Compact Framework 2.0 SP2」をインストールすることによってデバッグで出来るようにはなりました。
「BinaryReader / BinaryWriter」についてもう少し調べてみます。
体試行錯誤の段階でのソースを掲載してしまったので、解釈に苦しむ点があったことをお詫びします。
FileStreamの解放処理については他のサイトのサンプルでは記述がなかったので、
fs.Close()だけいれてました。

    '// alngGyo:あらかじめ特定された行
    '// astrBuff:書き込む内容(半角13桁)バーコードです。
    Private Function Dat_Write(ByVal alngGyo As Long, ByVal astrBuff As String) As Boolean
        Dim fs As System.IO.FileStream
        Dim byteBuff(13) As Byte

        Try
            '// ファイルオープン
            fs = New System.IO.FileStream("ファイル名", IO.FileMode.Open, IO.FileAccess.ReadWrite)

            '// Seek処理(一行117桁で24桁目から上書きを行うため)
            fs.Seek(alngGyo * 117 + 24, System.IO.SeekOrigin.Begin)

            '// Byte変換
            byteBuff = System.Text.Encoding.GetEncoding("shift-jis").GetBytes(astrBuff)

            '// 書き込み処理
            fs.Write(byteBuff, 0, byteBuff.Length)
            fs.Close()
            Return True

        Catch ex As Exception
            'MsgBox("ファイル書き込みエラー", MsgBoxStyle.OkOnly)
            fs.Close()
            Return False

        End Try

    End Function
解決済み!
■No21938に返信(向井さんの記事)
例外処理について、幾つか問題があるように見受けられます。

まず、解放処理は、Finally に書くのが一般的です。

また、As Exception で全ての例外を処理してしまうというのは、少々
乱暴すぎるように思えます。この場合は、ファイル入出力関係の例外など、
本当に必要な例外のみを捉えるようにし、それ以外の例外については、
そのまま処理させずに通過させた方がよろしいかと。
http://www.ailight.jp/blog/kazuk/articles/6298.aspx


もし、一切のエラーを通過させず、エラー発生時には戻り値 False として
返したいのだとしたら、現在のコードは、ファイルを開く際にエラーが
発生した場合に対応できていません。

New FileStream(…) の処理が失敗した場合、変数 fs は Nothing のままと
なりますが、現在のコードでは、
> Catch ex As Exception
>  'MsgBox("ファイル書き込みエラー", MsgBoxStyle.OkOnly)
>  fs.Close()
の部分で、fs にインスタンスが割り当てられていない場合にも、Close 処理を
呼び出すことになるため、ここでさらなるエラーが発生してしまいます。

Close を呼び出す前には、fs の状態を確認するようにしましょう。


もう一つ。最初に 14 バイト分の配列を
> Dim byteBuff(13) As Byte
として生成しているようですが、この配列は利用されていないようです。
実際には、その後の
> byteBuff = System.Text.Encoding.GetEncoding("shift-jis").GetBytes(astrBuff)
の部分で、最初にあった 14 バイトの配列は破棄され、別の配列が
代入されていますので、宣言部は、Dim byteBuff() As Byte でも良いかも。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板