アプリ版:「スタンプのみでお礼する」機能のリリースについて

VBScript初心者です。

現在、以下のような処理をさせるVBScriptを組もうとしています。

1.外部からファイルAを取得し、特定部分を抽出し、ファイルBとして保存
2.外部から取得したファイルCと、ファイルBを結合してファイルDとして保存
3.ファイルDの重複行を削除し、ファイルEとして保存

知りたいのは、上記のように一時ファイルを作成しながらファイルE(目的の成果物)を
作るのがよいのか、一時ファイルを作らずに、内部変数で一時データ情報を持って置き、
ファイルEを作るのがよいのか、ということです。もしかしたら他にもいい方式が?

メモリやCPUなどの負荷や、プログラム上の効率など、気にする点があると思っていますが、
初心者につき判断できておりません。ご教示をお願いしたく質問した次第です。

感覚でしかありませんが、登場するファイル数が多くないか?とは思っており、
外部から取得するファイルA,Cは仕方ないとして、ファイルB,Dは所詮一時ファイルで
冗長だとは何となく思っています。
しかし、効率が「悪そうだ」とは思っても「悪い」と言い切れるだけの知識はありません。

よろしくお願いします。

なお、参考ですが、
ファイルA:100万行
ファイルB:100万行(ただしA内の4カラムだけ抽出)
ファイルC:50万行(カラム数はBと一緒)
となります。

A 回答 (2件)

#1のかたもいわれているように


100行+50万行程度であれば、内部メモリに格納して処理可能です。
一般的には、内部メモリに格納しなくて処理できるなら、わざわざ内部メモリ格納にする必要は有りませんが、今回のケースでは、”重複行の削除”をおこなう為、その部分は、内部メモリに格納する必要があります。

各工程ごとに中間ファイルを作っていますが、このやりかたの良い点は以下の部分です。
1.各工程の作業がシンプルである。
2.その為、他人がメンテナンスしやすい。
欠点は、以下の点です。
1.中間ファイルを作るため、処理時間がかかる。
2.中間ファイルを作るため、ハードディスクの資源を無駄に食う。
上記の欠点が、運用上、問題にならないなら、この案でよいと思います。

但し、今回の場合は、作業ファイルを作らない方法でも、それほど、複雑なプログラムにはならないか思います。
以下の手順で行えば、それが可能です。
1.ファイルAを1行読み込み、4カラムを取得する。
2.その取得したデータが重複していなければ、ファイルEへ出力する。
  重複しているなら、破棄する。(重複の判断方法は後述)
3.上記をファイルAの全行ぶん繰り返す。
4.ファイルCを1行読込、そのデータが重複していなければ、ファイルEへ出力する。
  重複しているなら、破棄する。
5.上記をファイルCの全行ぶん繰り返す。

結論としては、どちらのやりかたでも良いと思います。
但し、各工程ごとに中間ファイルを作る場合でも、直接ファイルEへ出力する場合でも
重複かどうかをどうやって判断するかです。
原始的な方法は、(普通の)配列にデータを格納し、その配列内を順に全て検索し、重複の有無を確認する方法です。
しかし、100万行分もある配列内をそのように検索するのは、現実的では有りません。
このような場合、連想配列を使用します。連想配列について、もしご存じなければ、別途インターネット等
で、その概念を調べてください。
一言で言えば、キーと値をセットで登録可能な、配列です。キーは、重複してはいけません。
キーは、今回でいえば、4カラムのデータになります。値は、今回は使用しませんので空白文字でよいです。
一般的には、氏名(キー)と住所(値)とすると、
氏名  住所
織田信長  名古屋
徳川家康 東京
のようになります。

以下のサンプルは、in.txtを読み込み、重複行を削除して、out.txtへ出力するサンプルです。
---------------------
Option Explicit
Dim objFileSys
Dim strScriptPath
Dim inFile
Dim outFile
Dim inStream
Dim outStream
Dim inText
dim inCtr
dim outCtr
dim mdict
'連想配列
Set mdict = CreateObject("Scripting.Dictionary")

Set objFileSys = CreateObject("Scripting.FileSystemObject")
strScriptPath = Replace(WScript.ScriptFullName,WScript.ScriptName,"")
'入力ファイル
inFile = objFileSys.BuildPath(strScriptPath,"in.txt")
'出力ファイル
outFile = objFileSys.BuildPath(strScriptPath,"out.txt")
'入力ファイルオープン
Set inStream = objFileSys.OpenTextFile(inFile, 1)
'出力ファイルオープン
Set outStream = objFileSys.OpenTextFile(outFile, 2,true)
inCtr = 0
outCtr = 0
'最後まで読み込む
Do Until inStream.AtEndOfLine = True
'1行読込
inText = inStream.ReadLine
'入力件数カウントアップ
inCtr = inCtr + 1
'読み込んだ行が連想配列に存在するか
If mdict.Exists(inText) Then
'存在するなら、そのデータは破棄(処理無し)
else
'存在しないなら
'連想配列に登録
mdict.add inText,""
'ファイルへ出力
outStream.Write( inText & vbCRLF )
'出力件数カウントアップ
outCtr = outCtr + 1
End If
Loop
'ファイルクローズ
inStream.Close
outStream.Close
Set inStream = Nothing
Set outStream = Nothing
Set objFileSys = Nothing

msgBox("完了" & "in=" & inCtr & " out=" & outCtr)

---------------------
このサンプルは、in.txtがファイルDに相当し、out.txtがファイルEに相当します。
このサンプルを改造すれば、ファイルAとファイルCから直接ファイルE作ることができます。
    • good
    • 0
この回答へのお礼

回答ありがとうございました!

重複削除方式まで紹介いただきありがとうございます。
重複削除については、昇順ソート→前行とのみ比較→同一の場合書き込まない というやり方で作成済ではありましたが、ご紹介いただいた方式も
検討してみたいと思います。

お礼日時:2015/10/21 00:07

1行100バイトだとすると、ファイルAが100MBなので、メモリ上に全部乗せて処理してもいいかと思います。

    • good
    • 0
この回答へのお礼

回答ありがとうございました!

メモリリソースとのバランスということですね。勉強になりました。

お礼日時:2015/10/21 00:09

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