- ベストアンサー
CSVファイルへの保存の際、データが途中で切れてしまいます。
はじめまして。初心者になりますが、よろしくお願いします。 visual basic 2008を使って、研究で数値シミュレーションを組んでいるのですが、 その値をcsv形式で出力した際に、値の終わりの方が消えてしまう現象が出てしまいます。 具体的には、(出力データ数,xの値,zの値)という形でファイルに書き込んでいくのですが、 出力データ数を1001個にした際、保存したファイルをExcelやメモ帳で開くと、 最後が、(991,0.111540025,0.2)といった形となってしまい。値の数が合わないのです。 他にも出力データ数の値を変えて試してみましたが、 出力データ数が101個の際には、実際保存されたのは97個 出力データ数が2001個の際には、実際保存されたのは1998個 出力データ数が5001個の際には、実際保存されたのは4988個 となります。 いずれも、途中は完全に保存されていて、最後の部分のみ保存されていない(途中で切られている)といった状況です。 デバッグで切られている部分も値が存在していることは確認できていますので、 おそらく保存する際の間違いだと思うのですが、原因がわかりません。 すみませんが、ご指導をお願いします。 (以下、保存のためのプログラムを記します) Private Sub RK_ToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Rk_ToolStripMenuItem.Click 'ルンゲクッタデータを保存するためのモジュール Dim myStream As Stream Dim saveFileDialog1 As New SaveFileDialog() Dim s As String = "" If save_flag = False Then MsgBox("Error!!" & vbLf & "データがありません。") Else saveFileDialog1.Filter = "csv files (*.csv)|*.csv|txt files (*.txt)|*.txt|All files (*.*)|*.*" saveFileDialog1.DefaultExt = "csv" saveFileDialog1.FilterIndex = 1 saveFileDialog1.RestoreDirectory = True saveFileDialog1.OverwritePrompt = True If saveFileDialog1.ShowDialog() = DialogResult.OK Then myStream = saveFileDialog1.OpenFile() Dim sw As StreamWriter = New streamWriter(myStream) If (myStream IsNot Nothing) Then For i As Integer = 0 To n s = t_temp(i).ToString & "," & x_temp(i).ToString & "," & z_temp(i).ToString sw.WriteLine(s) Next i myStream.Close() MsgBox("ファイルへの書き込みが終了しました") End If End If End If End Sub
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
Flashを呼ぶとは StreamやStreamWriterのFlashメソッドを呼ぶということです Closeを実行する前に sw.Flash() myStream.Flash() などを挿入してみてください 投稿されているコード内容は実際に不具合の出るコードと同じなのでしょうか Try/Catchなどの例外処理などはされていませんか
その他の回答 (5)
- kunkun_129
- ベストアンサー率64% (16/25)
ANo.4の回答で1行間違っていたので再度書き込みます。失礼しました。 ソースを見て感じた事と最後に解決へのヒントを述べたいと思います。 貴方のソースから見ると、 ファイルのOpen for 書き込み内容の処理 ファイルへの書き込処理 next ファイルのClose 大まかに上の様になっています。今回のサンプルプログラムは 書き込み内容の処理、ファイルへの書き込処理それぞれ1行づつの 単純なものなので、さほど問題もないが、それでも原因不明のバグ に悩まされるものです。ソースを見る限りなぜ書き込みがうまくいかない のか不思議です。 ただ言える事は、ソースがバグの出やすい構造になっている事です。 故に原因が、ファイルへの書き込みで起こっているのか、書き込み内容の 作成段階で間違っているのか、原因がつかみにくいです。 上の様なソースの書き方は、CPUのメモリの少なかった時代(10年前) のソースの書き方だとおもいます。 現在では、メモリは使いきれない位あるので下の様にコーディングする 事を進めます。そうする事によって、バグが発見し易くなります。 '--------------------------------------------------------------- ' 変数に書き込み内容をどんどんためていきます。 '--------------------------------------------------------------- s="" For i As Integer = 0 To n s += t_temp(i).ToString & "," & x_temp(i).ToString & "," & z_temp(i).ToString ' <==== ここが間違っていた。 S+= の「+」が抜けていました。 Next i ' <========== '--------------------------------------------------------------- ' ファイルの書き込み '--------------------------------------------------------------- myStream = saveFileDialog1.OpenFile() Dim sw As StreamWriter = New streamWriter(myStream) sw.WriteLine(s) myStream.Close() 上の様にコーディングする事によって、利点は沢山あります。 (1).<==== のマークでブレークポイントを設けて変数Sの内容を 確認する事によって、今回の内容が、ファイルへの書き込みで起こっているのか、 書き込み内容の作成段階で間違っているのかはっきりする。 (2).今回は For と Next の間の行がわずか2行ですが、大きなプログラムだと 20行も30行もある時があります。 そうすると、ファイルへの書き込みとデータの作成が混在してどこでバグが 出ているのか判りにくい。分ける事によってバグが出にくくなります。 (3).ファイルはハードディスクを利用する為、出来るだけ、ファイルのOpenとClose は短時間で処理するのが理想です。ファイルをOpenしたら出来るだけ1行で 書き込み、直ぐにCloseする事によって、ハードディスク等の破損を防ぐ事が できます。 (4).ファイルStreamに書き込むより、変数にデータを書き込むのがレスポンスが 格段に早い 以上、解決のヒントになれば幸いです。
お礼
>>kunkun_129 様 わかりやすい丁寧な解説、どうもありがとうございました。 ご指摘の通り、変数への書き込みの後にファイルへの書き込みを行うと、確かにうまく書き込むことができました。 ファイルのOpenとCloseに関しては、できるだけ早く書き込むことがハードディスク的にも安全なのですね。初めて知りました。 バグを少なくするための考え方や、レスポンスの観点なども勉強になりました。本当にありがとうございました。 なお、redfox63様のご指摘(Stream.Flushメソッドを加えるだけ)でも、うまくいきましたことをご報告します。 (いただいたプログラムで s += t_temp(i).ToString & "," & x_temp(i).ToString & "," & z_temp(i).ToString & vblf と変更しました)
- kunkun_129
- ベストアンサー率64% (16/25)
ソースを見て感じた事と最後に解決へのヒントを述べたいと思います。 貴方のソースから見ると、 ファイルのOpen for 書き込み内容の処理 ファイルへの書き込処理 next ファイルのClose 大まかに上の様になっています。今回のサンプルプログラムは 書き込み内容の処理、ファイルへの書き込処理それぞれ1行づつの 単純なものなので、さほど問題もないが、それでも原因不明のバグ に悩まされるものです。ソースを見る限りなぜ書き込みがうまくいかない のか不思議です。 ただ言える事は、ソースがバグの出やすい構造になっている事です。 故に原因が、ファイルへの書き込みで起こっているのか、書き込み内容の 作成段階で間違っているのか、原因がつかみにくいです。 上の様なソースの書き方は、CPUのメモリの少なかった時代(10年前) のソースの書き方だとおもいます。 現在では、メモリは使いきれない位あるので下の様にコーディングする 事を進めます。そうする事によって、バグが発見し易くなります。 '--------------------------------------------------------------- ' 変数に書き込み内容をどんどんためていきます。 '--------------------------------------------------------------- s="" For i As Integer = 0 To n s = t_temp(i).ToString & "," & x_temp(i).ToString & "," & z_temp(i).ToString Next i ' <========== '--------------------------------------------------------------- ' ファイルの書き込み '--------------------------------------------------------------- myStream = saveFileDialog1.OpenFile() Dim sw As StreamWriter = New streamWriter(myStream) sw.WriteLine(s) myStream.Close() 上の様にコーディングする事によって、利点は沢山あります。 (1).<==== のマークでブレークポイントを設けて変数Sの内容を 確認する事によって、今回の内容が、ファイルへの書き込みで起こっているのか、 書き込み内容の作成段階で間違っているのかはっきりする。 (2).今回は For と Next の間の行がわずか2行ですが、大きなプログラムだと 20行も30行もある時があります。 そうすると、ファイルへの書き込みとデータの作成が混在してどこでバグが 出ているのか判りにくい。分ける事によってバグが出にくくなります。 (3).ファイルはハードディスクを利用する為、出来るだけ、ファイルのOpenとClose は短時間で処理するのが理想です。ファイルをOpenしたら出来るだけ1行で 書き込み、直ぐにCloseする事によって、ハードディスク等の破損を防ぐ事が できます。 (4).ファイルStreamに書き込むより、変数にデータを書き込むのがレスポンスが 格段に早い 以上、解決のヒントになれば幸いです。
- redfox63
- ベストアンサー率71% (1325/1856)
書き込んでいる先はローカルドライブでしょうか? StreamやStreamWriterをCloseする前に Flashを呼んでみても一緒ですか
補足
お手数をおかけしています。 >>書き込んでいる先はローカルドライブでしょうか? デスクトップやドキュメント内にcsvファイルとして保存させ、それをExcelやメモ帳で開いて確認しています。OSはvistaです。 >>StreamやStreamWriterをCloseする前に Flashを呼んでみても一緒ですか? 申し訳ありません。「Flashを呼ぶ」の部分がよくわかりませんでした。 下記サイトのように、あらかじめ用意しておいたswfファイルに、値を読み出すということでしょうか? http://www.crossdrive.net/tips/vb_each_swf
- iriyak
- ベストアンサー率48% (40/82)
こんにちは。 机上ベースですが・・・ 1. StreamWriter に writeLine してもらって close してもらうのでは?? プログラムは、myStream に close を送っているように見えます。 2. New StreamWriter でインスタンスオブジェクトの生成にトライしていますが、myStream が Nothing か比較していますが、これも sw 変数に代入されたかどうかを検査したかったのでは??
お礼
ご指摘ありがとうございました。
補足
こんにちは。お手数をおかけしています。 初心者故の間違いをお許しください。 この部分のプログラムに関しては、msdnの以下のサイトのサンプルコードを基に設計したのです。 1.で指摘していただいた間違いには気付きませんでした。 2.に関してですが、おそらくsavefiledialogで代入されたファイル名(=mysteam)が 空欄でないかをチェックしているものと思っているのですが。(間違いかもしれません。) http://msdn.microsoft.com/ja-jp/library/system.windows.forms.savefiledialog.openfile.aspx http://msdn.microsoft.com/ja-jp/library/6ka1wd3w(VS.80).aspx 早速、以下のように修正したのですが、問題は解決されませんでした。 (上記サイトではUsingが使われていたので、それも試してみたのですが。) 間違いがありましたら、ご指摘ください。 (以下、修正されたプログラムを記します) Private Sub RK_ToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Rk_ToolStripMenuItem.Click 'ルンゲクッタデータを保存するためのモジュール Dim myStream As Stream Dim saveFileDialog1 As New SaveFileDialog() Dim s As String = "" If save_flag = False Then MsgBox("Error!!" & vbLf & "データがありません。") Else saveFileDialog1.Filter = "csv files (*.csv)|*.csv|txt files (*.txt)|*.txt|All files (*.*)|*.*" saveFileDialog1.DefaultExt = "csv" saveFileDialog1.FilterIndex = 1 saveFileDialog1.RestoreDirectory = True saveFileDialog1.OverwritePrompt = True If saveFileDialog1.ShowDialog() = DialogResult.OK Then myStream = saveFileDialog1.OpenFile() If (myStream IsNot Nothing) Then ' Code to write the stream goes here. Using sw As StreamWriter = New StreamWriter(myStream) For i As Integer = 0 To n s = t_temp(i).ToString & "," & x_temp(i).ToString & "," & z_temp(i).ToString sw.WriteLine(s) Next i sw.Close() End Using MsgBox("ファイルへの書き込みが終了しました") myStream.Close() End If End If End If End Sub
- bin-chan
- ベストアンサー率33% (1403/4213)
Forループの回数を制御する変数nはどこで宣言されているのでしょうか? モジュールの引数として渡されているようには見えません。 本当に「nは意図する回数の値」になっているのでしょうか? 定数とすることはできませんか? h
補足
お手数おかけします。 ・nの定義について nはクラスの最初に宣言ステートメントで、他の変数と共に Dim n As Integer = 100 '区間の数 Dim t_temp(n), x_temp(n), z_temp(n) As Double と定義しています。 その後、nをコンボボックスの値を代入するために、あるボタンを押すと n = Val(combo_n.Text) ReDim t_temp(n), x_temp(n), z_temp(n) '要素数の変更に対応するため再定義 となるようにしています。 その後、t_temp(n), x_temp(n), z_temp(n)はある関数で計算されます。(値を見ると正しく計算されているようです。) ・nの値の確認 先ほどのプログラムの saveFileDialog1.OverwritePrompt = True の下に Debug.Print(n) Debug.Print(z_temp(n)) Debug.Print(z_temp(n - 1)) Debug.Print(z_temp(n - 2)) Debug.Print(z_temp(n - 3)) を入れて確認してみたところ、私が意図した値となっていました。 しかし、保存すると、数が少なくなってしまいます。 また、先ほどのプログラムでnの部分を定数にしてみたのですが、 同じ結果となりました。
お礼
>>redfox63 様 ご指摘いただいたように sw.Flush() myStream.Flush() のどちらかを組み入れるだけで、最後までうまく保存できました。 どうやらバッファの情報がうまくファイルに送信されていなかったことがうまくいかなかった原因のようです。 それがなぜ起こったかは、まだよくわかっていないのですが、kunkun_129さんの方法でもうまくいったということからも考えると、ファイルの入力処理を頻繁にやりすぎたことも、その一つの原因かもしれません。 おかげで原因がわかり、解決もできましたので、回答を締め切らせていただきます。お手数おかけしました。 >投稿されているコード内容は実際に不具合の出るコードと同じなのでしょうか そのとおりでした。 >Try/Catchなどの例外処理などはされていませんか 例外処理は使っていませんでした。