|
お世話になります。 現在、230カラムあるCSVデータを50,000件(行)作ろうとしています。 FOPENでファイルを開き、230個のFPUTを並べてそれをFor〜Nextで回してFCLOSEしようとしています。 最初何も考えずにいきなり50,000回ループさせようとしたらOut of memoryになりまして(当然です)とりあえず5%(2500行)毎にFCLOSEして再度FOPENしようと思いました。 そうしたら10%までは普通に動くのですが、15%時点でFCLOSEしようとした時にエラーになり、Can't be written inが出てエラーになってしまいます。 FOPENで-1を返してFCLOSEの時にエラーを吐いているのかと思いましたが、ログに出力してみた所、FOPENの時点では1を返していました。
以下にスクリプトを載せます。 その前にExcel開いて別のcsvファイルからヘッダ行を取得したりしてるのでわからない所があるかもしれませんが…
*************************************************************************************
〜(前略)〜
Public total = 50000
//新規ファイル作成 FNAME = "C:\uwsc511\" + sheet_name + ".csv" DOSCMD("type null > " + FNAME)
//CSVファイルオープン ID = FOPEN(FNAME,F_READ or F_WRITE or F_EXCLUSIVE) GETTIME()
PRINT "処理開始" PRINT G_TIME_HH2 + "時" + G_TIME_NN2 + "分" + G_TIME_SS2 + "秒:ファイルオープン" PRINT "ファイルオープン結果:" + ID
//ヘッダー行記入 x = 1 For i = 0 to endcell-2 FPUT(ID,"<#DBL>" + box_num[i] + "<#DBL>",1,x) x = x + 1 Next
//データ行記入 x = 1 y = 1
For i = 1 to total fukidasi(KEISAN(x) + "%完了…")
FPUT(ID,mIDgen(x-1),y+1,1) //1 申込ID FPUT(ID,mMBANGOUgen(x-1,13),y+1,2) //2 申込番号 FPUT(ID,mNUMgen(20),y+1,3) //3 申込番号 FPUT(ID,mDAYgen(),y+1,4) //4 申込日 FPUT(ID,mDAYgen(),y+1,5) //5 申込実施日 FPUT(ID,mDAYgen(),y+1,6) //6 異動年月日 FPUT(ID,mDAYgen(),y+1,7) //7 開始予定日 FPUT(ID,mDAYgen(),y+1,8) //8 終了予定日 FPUT(ID,P00029(17),y+1,9) //9 申込種別
(これが230個続く)
Ifb (i MOD 2500) = 0 then Dim FC = FCLOSE(ID,TRUE) PRINT "書き込み結果:" + FC + "<#CR>" PRINT "<#CR>処理状況" + KEISAN(x) + "%" Repeat GETTIME() Sleep(0.5) PRINT G_TIME_HH2 + "時" + G_TIME_NN2 + "分" + G_TIME_SS2 + "秒:ファイル書き込み中..." Until FC = 1 GETTIME() PRINT G_TIME_HH2 + "時" + G_TIME_NN2 + "分" + G_TIME_SS2 + "秒:書き込み完了"
ID = FOPEN(FNAME, F_READ or F_WRITE or F_EXCLUSIVE)
GETTIME() Sleep(0.5) PRINT G_TIME_HH2 + "時" + G_TIME_NN2 + "分" + G_TIME_SS2 + "秒:ファイルオープン"
GETTIME() PRINT "ファイルオープン結果:" + ID PRINT G_TIME_HH2 + "時" + G_TIME_NN2 + "分" + G_TIME_SS2 + "秒:処理再開" Endif
x = x + 1 y = y + 1 Next
FCLOSE(ID,FALSE) *************************************************************************************
省いてる所もありますがこんな感じです。 一つ気になっているのが、FCLOSEすればFPUTの間に使用していたメモリは解放されるのかと思っていたのですが、タスクマネージャーを見ていた所、どんどんメモリの使用量が増え続けています。これはこういうものなんでしょうか…また、これが原因ということはありますか?
色々書きましたがご教示下さい。よろしくお願い致します。
|
No.1438 2015/07/09(Thu) 17:22:25
|
☆ Re: Can't be written in / stuncloud |
|
|
> F_READ or F_WRITE だと一旦ファイルの中身を全部読み取ってるようなのでファイルサイズが肥大化していくと困ったことになっちゃうんですよね 以前ログの書き出しに一行毎にfopen-fput-fcloseとやってたことがあったんですが、ファイルサイズが大きくなるほど書き込みに時間がかかるようになって困った覚えがあります Excelをご利用のようですし、csvへの書き出しもExcelにしてみてはどうでしょうか? (Excelは5万行…扱えましたよね?)
|
No.1439 2015/07/09(Thu) 18:24:31
|
|
☆ Re: Can't be written in / アソビン |
|
|
追記ですが、今、他のデータ(カラム数がそこまで多くなく40カラム程度)を実行させてみたら何事もなく完了しました。 やはりメモリとかでしょうか…?
|
No.1440 2015/07/09(Thu) 18:25:07
|
|
☆ Re: Can't be written in / アソビン |
|
|
☆stuncloudさん オラクル用のデータで、ダブルクォーテーション括りのカンマ区切りなのでExcelだとうまくいかないんですよね。。。 やり方があるのかもしれませんが。
|
No.1441 2015/07/09(Thu) 18:29:59
|
|
☆ Re: Can't be written in / しき |
|
|
UWSCの fopen-fput-fclose は、 fputした文字をすべて保持(変数に入れるようなもの)して、 fcloseした時に実際のファイルに反映します。 書き出すファイル内容分だけのメモリを消費します。
また、fopen(file, f_read) した時に、fileの内容をすべて読み込むので、 途中で fclose-fopen してもメモリの節約にはなりません
Scripting.FileSystemObject の TextStreamを使った方法を紹介します TextStreamは上から下への一方向しか制御できませんが、 WriteLine()ごとファイルに反映するので、巨大なテキストファイルを扱うのに有効です
//参考URL //WriteLine メソッド (FileSystemObject) //https://msdn.microsoft.com/ja-jp/library/cc428063.aspx
//OpenTextFile メソッド //https://msdn.microsoft.com/ja-jp/library/cc428044.aspx
Public total = 50000 //新規ファイル作成 FNAME = get_cur_dir+"\abc.csv"
o_Fs = CreateOleObj("Scripting.FileSystemObject") ForWriting = 2 //ファイルを書き込み専用として開きます ofw = o_Fs.OpenTextFile(FNAME, ForWriting, true)
//ヘッダー行記入 ofw.WriteLine("申込ID,申込番号,申込日")
fid = fopen("", f_read or f_write) //一行データ作成用
//データ行記入 for i=1 to total ifb (0 = (i mod 100)) then fukidasi(int((i/total)*100)+"% "+ i +"/"+ total) endif fput(fid, i +"行1列", 1, 1) fput(fid, i +"行2列", 1, 2) fput(fid, i +"行3列", 1, 3) dim s_line = fget(fid, 1) ofw.WriteLine(s_line) //一行データ書き出し fput(fid, "", 1) //一行目消す next
fclose(fid) ofw.Close()
|
No.1442 2015/07/09(Thu) 18:39:27
|
|
☆ Re: Can't be written in / アソビン |
|
|
☆しきさん おおおおおおおおおおおおおお!ありがとうございます! これは……凄い!完璧ですね!! サンプルで書いて頂いたコードを実情に合わせて自分なりに手を加えてみましたが、完全に動作しています。 FOPENでNULLを指定して仮想ファイルを開いているようなイメージですか?こんな使い方があったとは。 処理速度も思った程遅くなく、むしろこれまで書き込み確認とかで余計な処理を入れてたことを思えばよりシンプルになって少し速くなってるくらいかもしれません。 (実際は50,000行も書き出してればその差もほとんどわかりませんがw)
今後、もっとカラム数が少ない場合のスクリプトもこの方式に置き換えて時間などの検証を重ねたいと思います。 大変参考になりました。どうもありがとうございました!!
|
No.1448 2015/07/10(Fri) 11:44:26
|
|