プロが教えるわが家の防犯対策術!

[VBScript]ファイルの入出力を同時に行う方法

以下の入力ファイルから以下の出力ファイルを作るアルゴリズムを考えていたのですが、
不明な点が出てしまい、アドバイスいただけないかと思い投稿しました。

不明な点は、掲題の通り、
「ファイルの入出力を同時に行うことが出来ないのではないか」という点です。

以下の入力ファイル形式を出力ファイル形式へ変換するには、
「セクション1」の「りんご」の行までは、入力ファイルを 1 行ずつ読み込んで
出力ファイルへ 1 行ずつ書き込めば良いと思います。

しかし、「セクション2」の「みかん」の「100」の文字列を出力ファイルへ書き込むには、
現在書き込み途中の出力ファイルの中を検索し、「みかん」の行が見つかったら
その隣に「,100」という文字列を書き込むという処理が発生します。

つまり、出力ファイルに対し、書き込みと読み込み(検索)を同時に行わければなりません。
このようなことが果たして可能なのか、以下のコードで確かめてみたのですが
エラーとなってしまいました。

やはり一旦出力ファイルをクローズするしかないでしょうか……?

■入力ファイル形式
・セクション1
いちご
みかん
りんご

・セクション2
みかん:100円

・セクション3
キウイ
バナナ
マンゴー

・セクション4
マンゴー:300円

■出力ファイル形式
いちご
みかん,100
りんご
キウイ
バナナ
マンゴー,300

■コード
Private Const overWrite = "True"
Private objFSO: Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Private objTextStream_out : Set objTextStream_out = objFSO.CreateTextFile(".\out.txt", overWrite)

objTextStream_out.WriteLine("いちご")
objTextStream_out.WriteLine("みかん")
objTextStream_out.WriteLine("りんご")

Private buffer_out : buffer_out = objTextStream_out.ReadAll()

A 回答 (3件)

ファイルの入出力方法はFileSystemObjectだけではありません。


ADODB.Streamオブジェクトを使うと、Positionプロパティを
操作することにより、任意の入出力ポイントに移動することが
可能です。この他、文字コードの変換やバイナリデータも扱う
ことができます。勿論、それだけ面倒な制御が必要ですが、そこは
頑張るしかないですね。以下はサンプルです。

Dim X, T, C
Set X = CreateObejct("ADODB.Stream")
A.Open
A.Type = 2 'テキスト形式を意味する。バイナリなら1
A.LoadFromFile "C:\~" 'ファイルを読み込むため開く
A.Position = 0 'ファイルの先頭に位置付ける
'---- 1行読み込み
T = ""
Do
    If A.EOS Then Exit Do '終端に達していれば終了
    C = A.ReadText(1) '1文字読み込む
    If C = vbLf Then Exit Do '改行なら抜ける
    T = T & C ’文字を結合する
Loop
'---- ファイルを書き込む
A.SaveToFile "C;\~", 2 '上書き許可を指定、不可なら1

この回答への補足

Option Explicit
Private Const forReading = 1
Private Const notCreate = "False"
Private Const ASCIImode = 0
Private Const overWrite = "True"
Private objFSO : Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Private objUtility : Set objUtility = New Utility
Private objTextStream_in01
Private objADODBStream_out01
Private filePath_in01 : filePath_in01 = ".\in01.txt"
Private filePath_out01 : filePath_out01 = ".\out01.csv"
Private buffer_in01
Private buffer_out01 : buffer_out01 = ""
Private fruitName
Private money
Private chr
Private flag_replaceMoney : flag_replaceMoney = False
Set objTextStream_in01 = objFSO.OpenTextFile(filePath_in01, forReading, notCreate, ASCIImode)
Set objADODBStream_out01 = WScript.CreateObject("ADODB.Stream")
objADODBStream_out01.Charset = "UTF-8"
objADODBStream_out01.Open
While Not objTextStream_in01.AtEndOfStream
  buffer_in01 = objTextStream_in01.ReadLine()
  If InStr(1, buffer_in01, "・セクション") = 0 And buffer_in01 <> "" Then
    fruitName = objUtility.getFruitName(buffer_in01)
    If InStr(1, buffer_in01, "円") <> 0 Then
      objADODBStream_out01.Position = 0
      Do
        If objADODBStream_out01.EOS Or flag_replaceMoney Then
          Exit Do
        End If
        chr = objADODBStream_out01.ReadText(1)
        If chr = vbLf And InStr(1, buffer_out01, fruitName) <> 0 Then
          money = objUtility.getMoney(buffer_in01)
          buffer_out01 = Replace(buffer_out01, "金額不明", money)
          flag_replaceMoney = True
        End If
        If chr <> vbLf Then
          buffer_out01 = buffer_out01 & chr
        Else
          buffer_out01 = ""
        End If
      Loop
    End If
    objADODBStream_out01.WriteText fruitName & ",金額不明" & vbCrLf
    objADODBStream_out01.Position = ???
    flag_replaceMoney = False
  End If
Wend

補足日時:2010/07/18 17:48
    • good
    • 0
この回答へのお礼

回答ありがとうございます。お返事遅くなりまして申し訳ございませんでした。

ADODB Stream オブジェクトは通常、DB 関係の処理に用いるものですが、
単なるファイル入出力にも活用できるとは思いつきませんでした。
有益なアドバイス感謝します。

コードを組んでみましたが(補足欄にアップしました)、
出力ファイル内でファイルを検索することは出来ても、
それを置換する処理はやはり難しそうです(書きかけ断念)。

今回、セクション 1, 2, 3, 4 が 1 つの入力ファイルに連続して書かれていると説明しましたが、
入力ファイル自体をセクション 1, 3 とセクション 2, 4 に分けることが可能なので、
セクション 1, 3 の情報を csv ファイル化し、セクション 2, 4 の情報も csv ファイル化して
マージする方法を取ることにしました。

この方法ですと、ADODB Stream オブジェクトの
ファイルポインタ操作が活用できることが確認できました。

サンプルコードは非常に参考になりました。ありがとうございました!

お礼日時:2010/07/18 17:50

ファイル入出力というものを、改めて勉強して、FSOが何処までのものがやれるか、勉強のこと。


FSOの勉強から初めてファイル入出力の一般理論を勉強しないから、変な質問になる。基本的にテキストストリームはフィールドの内容を変えて、直にその場所に書き戻しが出来ない。
C言語などから来るストリームの考え方とは。
IBM大型事務系(および国内大型)OSなどなどは早くから色々なファイルシステムが考えらていた。
パソコンではこれらをあいまいにした上で説明がなされやすい。
昔のBasicにあったRandomAccess(固定長レコードで、レコード番号でアクセス)などはいまでは影が薄いようだ。
(ランダムアクセスとシーケンシャルアクセス)
ファイル構造(索引などを持ったファイル入出力)を持ったファイルと単純アクセスファイルなどの違い。
普通人は、検索などはADOのSQLなどに任せる場合が多く、自分で検索に便利なファイルシステムを自作する時代ではない。
パソコンに出てくるのは、ファイル構造は無いテキストファイルで
下記はすべて先頭からの順次処理になる。(シーケンシャルアクセス)
かつ最後からの逆戻り処理は普通は扱わない。
読み出し専用  これは議論ないだろう
書き込み専用 これもゼロの中身のファイルに一方的に順に書いていく。
追加書き込み専用  いま在るファイルの最後のレコードの次に書き込み追加を許すモード。Appendモード
書き込み修正 いま在るファイルの1部を修正して物理的に同じ場所に書き戻すということ。 これは通常しない・出来ない
       其れで変更ない部分も新しいファイルに順次書き、修正する箇所は、アウトプットファイルの修正する箇所に来たとき、新しいファイル(アウトプットファイル)のその個所に修正したものを書く。修正前の部分は使わない。
ーーー
WriteLineメソッドはどれですか。無批判に使っているのでは。
ーー
以上は最終ファイル(通常ディスク)に記録する場合のことをいっているので、書く前段階として、フィールドの内容を示す変数の値の変動、フィールド数の変動は関係ないことだ。
だからその段階では変数にデータをとどめておいて、終了(確定)時に書き出せば済むことでは在る。
ーー
>セクション2
セクションという言葉はコンピュター界では良く出てきます。
突然質問で使っても何の意味で言っているのか判らない、。難しい言葉を無批判に使わないこと。
ーー
質問者は、上記に出てきた語句を中心に、WEBで照会でもして、勉強し、頭を整理してから質問すべきように思う。

この回答への補足

失礼ですが、あなたは結局、私の質問には答えられるのでしょうか?
こちらとしては FileSystemObject を絶対に使いたいという気持ちがあるわけではありません。
何らかの手段を用いて、書き込みと読み込みを同時に行いたいだけです。

補足日時:2010/07/18 17:27
    • good
    • 0

「みかん:100円」という行を読み込んだ時、この文字列を「みかん,100」に変換して出力する方法はいかがでしょうか。




Dim fso
Set fso = WScript.CreateObject("Scripting.FileSystemObject")

'入力ファイルオープン
Dim tsi
Set tsi = fso.OpenTextFile(".\in.txt", 1)

'出力ファイル作成
Dim tso
Set tso = fso.CreateTextFile(".\out.txt", true)

'入力ファイルを1件読み込みながら、出力ファイルに値を出力する。
Do Until tsi.AtEndOfStream = true
Dim line
line = tsi.ReadLine
'(空行、「セクション」行)以外を処理対象とする。
If Len(line) > 0 And InStr(line, "セクション") <= 0 Then
'「:」があったら「,」に変換
line = Replace(line, ":", ",")
'「円」があったら削除
line = Replace(line, "円", "")
'結果を書き込む
tso.WriteLine(line)
End If
Loop

tsi.Close
tso.Close


上記の例は、入力ファイルと出力ファイル2つをオープンし、処理を行なっています。
オープンした1つのファイルに読み書きを同時に行なうのはわかりにくいため、私はあまりやりません。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。お返事遅くなりまして申し訳ございませんでした。

いただいたアイディアについてなのですが、
この場合ですと、「みかん」に関する行が 2 つ出力されると思います。
それを回避する方法をご存知でしたら補足いただけると幸いです。

お礼日時:2010/07/18 17:22

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています