ファイル操作に関して、こんなことできますでしょうか

解決


ひよこ  2005-05-20 05:05:58  No: 121780

テキストファイルをOPENして、最終行まで読み込んで、CLOSEするという
処理を『同じファイル』に対して何回も行いたいのですが、
上手くいきません。
以下のような関数を何回も呼び出す形なのですが、
二回目になると★印のところでループしないで処理を抜けてしまいます。

------------------------------------------------------------------
Private Function Sumple_Src() As Boolean

    〜変数定義省略〜

    l_intFileNo = FreeFile
    l_strFileName = "AAA.txt"
    Open l_strFileName For Input As l_intFileNo
    Do While Not EOF(l_intFileNo)  ←★
        l_strData = l_strData & Input(1, l_intFileNo)     
    Loop
    Close l_intFileNo
    
    〜省略〜

End Function
------------------------------------------------------------------

一回目にこの関数を呼び出すときは
ちゃんと最終行まで読み込めるのですが、
二回目にこの関数をよびだすと、★印のところで一回だけループして
抜けてしまいます。
二回目になると読込位置が既にEOFになっているような感じです。
ファイルを一旦クローズしても、「最終行まで読み込んだ」という
情報がメモリとかどっかに残っているということなのでしょうか?
理由が分からず困っています。
また、ならば読込位置を一旦ファイルの先頭に戻すという処理を
入れてあげればいいのかと考えましたが、どういうソースを書けば
いいのか、わからない状態です。

どなたか教えていただけないでしょうか
よろしくお願いします。


Boo  2005-05-20 05:41:50  No: 121781

同じコードで試してみましたが、ちゃんと何回やっても全て読み取るようですね。
残念ながらこちらの環境(WinXP SP2, VB6 SP6)再現しませんでした。
ただ、読み取るデータが提示されてませんでしたので適用に
1
2
3
4
5
6
7
8
9
10
というようなテキストファイル(AAA.txt)を作成してやってみました。


いな  2005-05-20 05:52:35  No: 121782

>再現しないね。

一応自分も作ってみたけどさ

Private Function Sample_Src() As Boolean
Next_Proc:
    '使用可能なファイル番号を取得
    intFileNo = FreeFile
    'テキストファイルをオープン
    Open "c:\aaa.txt" For Input As #intFileNo
    ' ファイルの終端までループを繰り返します。
    Do While Not EOF(intFileNo)
        '1 行づつ変数に読み込みます。
        Line Input #intFileNo, strTextLine
        MsgBox strTextLine
    Loop
    'ファイルを閉じる
    Close #intFileNo
    
GoTo Next_Proc:
End Function

無限ループ注意


ひよこ  2005-05-20 06:30:59  No: 121783

Booさん、いなさん
試していただいてありがとうございます。

再現しないということで、
余計な時間を取らせてしまいすいませんでした。

私の環境(WinXP SP1、VB6.0)では、事象が発生し続けています。
何が原因なんだろう。。。
ただ、お二人のおかげで関数の中身自体は問題がなさそうということは
分かったので、関数を呼び出している方などを調べてみます。

ありがとうございました。


いな  2005-05-20 07:04:52  No: 121784

一応あがいてみようかな。。。
相対パスを絶対パスにしてみる。。。とか(く、苦しい)

 l_strFileName = "AAA.txt"

 l_strFileName = App.Path & "\AAA.txt"

どこかで、
カレントフォルダ移動している処理があったり、無かったり


魔界の仮面弁士  2005-05-20 08:17:29  No: 121785

> 〜省略〜
呼び出し部も含めて、再現できるコードになっていれば、
検証しやすいのですけれどね。

> 二回目にこの関数をよびだすと、★印のところで一回だけループして
> 抜けてしまいます。
『二回目の呼び出し』時であっても、
(0回ではなく)1回だけはループするのですね?

という事は、『l_strData = l_strData & Input(1, l_intFileNo)』の行は、
一度だけ実行されるのだと思います。ではその時、変数 l_strData の内容は、
この行の実行の前と後とで、期待値通りの値になっているか、確認してみては。

> 二回目になると読込位置が既にEOFになっているような感じです。
実際に、きちんと確認してみましょう。
Seek関数を使えば、現在の読み込み位置がわかりますよ。
 Debug.Print "FileNo:"; l_intFileNo, "Position:"; Seek(l_intFileNo)

とりあえず、疑うとすれば……

・Open時に、InputモードとOutputモードを間違えている箇所はありませんか?
 (1回目と2回目で、ファイルサイズが変化していたりはしませんか?)

・Option Explicitを宣言してありますか?
 (スペルミスが原因で、想定外の動作になっているとか)

・むやみに、モジュールレベル変数を宣言していませんか?
 (他のプロシージャで、変数の値をうっかり変えてしまう可能性がある)

・Open前後で、カレントドライブやカレントディレクトリは移動していませんか?
 (いなさんが書いたように、フルパスを使った方が安全です)

・Sumple → Sample ではありますまいか。
 (どうでも良いことですけど)


ひよこ  2005-05-20 08:32:40  No: 121786

>相対パスを絶対パスにしてみる。。。とか(く、苦しい)
早速やってみました。
ファイルの存在確認もできるように以下のような形で
やってみました。

l_strFileName = Dir(App.Path & "AAA.txt")
If l_strFileName = "" Then
   'ファイルが無い時の処理
End If

毎回関数が呼ばれる時にちゃんと同じファイルを
OPENできているのですが、事象は解消できませんでした。
この関数以外にファイル操作をしている箇所はないんですが、
原因はわからないままです。

ただ、新規にプロジェクトファイルを作って、
問題の関数のみ抜き出してやってみたら上手くいっちゃいました。
やはり、今作っているプログラムに問題があるみたいで、
関数が大分深いところにあるので、呼び出すタイミングを
いろいろと変えてみたりしているのですが、
まだ原因と思われるものにすらたどりつけていません。
もう少し、頑張ってみてダメであったら、ファイルを複数個
用意して、別の名前にするなどで別の手立てを考えようと思います。


ひよこ  2005-05-20 09:07:15  No: 121787

>『二回目の呼び出し』時であっても、
>(0回ではなく)1回だけはループするのですね?
ごめんなさい。
ループはしていませんでした。
ループ0回で処理を抜けています。

>実際に、きちんと確認してみましょう。
>Seek関数を使えば、現在の読み込み位置がわかりますよ。
> Debug.Print "FileNo:"; l_intFileNo, "Position:"; Seek(l_intFileNo)
ありがとうございます。
確認してみました。
ちなみにファイルは固定長のテキストファイルで、
1行80バイトで22行あります。
改行コードを含めて全部で1804バイトのファイルです。

一回目はループするので、処理が終わると
読込位置は1805になっています。
二回目はループしないので、読込位置は1のままでした。
二回目もちゃんと同じファイルをみれているのかが
疑わしくなってきました。
(フルパス指定にしたのですが、何か別の問題があるのかも)


id_rsa+  2005-05-20 11:39:15  No: 121788

>l_strData = l_strData & Input(1, l_intFileNo)   


これはおかしくないかい????
Input #filenumber, varlistだよね。。


ガッ  2005-05-20 16:24:31  No: 121789

> id_rsa+さん
Input()も有りますし、構文としては問題ないように思いますが…?

> ひよこさん
> 新規にプロジェクトファイルを作って、
> 問題の関数のみ抜き出してやってみたら上手くいっちゃいました。
うーん…
名前の競合が起こっているかもしれませんので、
一応[_HiddenModule].Input()にしておいたほうがいいかもしれないですね。

※なんか激しく誤爆かも(orz


ひよこ  2005-05-20 22:59:47  No: 121790

原因が分かり解決できました。

以下の二点が原因でした。
①問題の関数のその後の処理で、自分で作ったDLLを呼出していて、
  Log出力を行っていた
②Dir関数を誤った認識で使用していた

後続処理で自分で作ったDLLを呼出していて、
そのDLLの中で処理結果をログファイルに出力していました。
この際にカレントディレクトリが、DLLのログファイルの出力先に
移動していました。
また、試行錯誤している中でOPENのモードを変えたりしてやって
いたので、その際にDLLのログファイル出力先に、今回処理したい
ファイルと同じ名前の0バイトファイルが出来上がっていたみたいです。
(これに気付いていませんでした。)

それと、Dir関数について誤った思い込みで使用していました。
Dir関数の結果として返ってくるのは、ファイルまたはフォルダの
名前だけなのですね。
l_strFileName = Dir(App.Path & "AAA.txt")
これで、絶対パス指定できているつもりになっていましたが、
存在確認自体は絶対パスでやっているが、
l_strFileNameに格納されるのは、"AAA.txt"だけで、
絶対パス指定になっていないという状態でした。

処理を順番でいくとこんな感じだったと思います。
①問題の関数実行
  (一回目は、期待通りのファイルをみれている。)
  ↓
②DLL呼出
  (カレントディレクトリ移動)
  ↓
③問題の関数実行
  (二回目は、DLLのログ出力先にあった0バイトファイルを
    みてしまっている。)

以下のように絶対パス指定で、変数に格納し直したら
上手くいきました。

l_strFileName = Dir(App.Path & "AAA.txt")
If l_strFileName = "" Then
   'ファイルが無い時の処理
End If
l_strFileName = App.Path & "AAA.txt"   ←★追加

最初は、実現可否について力を借りたいというつもりで
質問したのですが、結局は自分のプログラムのバグでした。
お騒がせしてすいませんでした。

お力添えをいただいた皆様ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加