- ベストアンサー
windows 環境でのファイル操作について
今作成しているjavaのアプリケーションがあるのですが、 うまく動きません。 ファイルサーバにアップロードされるファイルを数秒間ごとに 監視し、アップロードされれば自動で別のディレクトリにコピ ーするというアプリケーションを作成しております。 で、MAC osX server上で動かすと正常に動くのですが、 Windows 2000 server上だと正常に動きません。 プログラムの流れとしてはFile型のorigオブジェクト(元ファイル) と、File型のcopyオブジェクト(移動先のファイル)を用意し、 BufferedInputSteramで読み取って、BufferedOutputStreamで 書き出す、というものです。 うまく動かない箇所は、origファイルがまだアップロード中で ある場合そのファイルに対してFileInputStreamを用意しようと すると、FileNotFoundExceptionが発生するだけでなく、その ファイルが消去されてしまうのです。恐らくはJavaではなく、 OSがコピーエラーが発生したかのように扱ってしまい、ファイル を消去してしまうのではないかと思っているのですが。(osXでは 動くので) FileInputStream fis = new FileInputStream(orig); この行で例外発生!ファイルが消える。 そこでFileInputStreamを用意する前に、そのファイルがコピー中 であるのか、コピーが終わっているのかを調べることができるの でしょうか、というのが私の質問です。あるいは、全く違った側面 からの回避策でも結構です。 ちなみにorig.exists()はアップロード中であってもtrueが返され ます。 javaはプラットホームに依存しないと信じてたのに大きな落とし穴 でした。以下にソースの一部を記述しておきますので、よろしく おねがいします。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
気になったんでちょっと試してみました。 環境は違うんですが、おそらく同じような結果が得られました。 環境:WindowsXP JVM:JDK1.3.1_02 コピー中のファイルに対しては確かにexistsがtrueになりました。 InputStreamを取得すると、 java.io.FileNotFoundException: test.txt (プロセスはファイルにアクセスできません。別のプロセスが使用中です。) という例外がthrowされました。 ここまで同じような結果が得られるのですが、 私が試した結果ではファイルは消えません。そのままコピーが継続されました。 例外が発生したときに何かしていますか? ファイルが消えてしまうのは何か別の原因ではないでしょうか?
その他の回答 (5)
- COOKY2
- ベストアンサー率28% (2/7)
問題のフォルダのオブジェクト.lists() で、ファイルやサブフォルダがString[]が返りますよね。 これで確認してからでは、いかがでしょうか?
補足
コピー中のファイルもFile型のオブジェクトとして認識します。
- a-kuma
- ベストアンサー率50% (1122/2211)
実は JVM の障害で、バージョンを上げたり/下げたりすると動く、ってことは… 後は、ファイルの時刻をコピー開始の時刻とみなして、適当な時間が経ってからコピーかなあ。
お礼
いろいろお騒がせいたしましたが、結局FileInputStreamを使わず、renameTo()メソドを試してみたらファイルの移動が問題なく実現いたしました。 問題が全て解決したわけではありませんが、一応自分のやりたかったことは実現できました。ありがとうございました。
補足
そうですね。原因がJVMの方にあるということも考えられなくはないです。 ですが、osXでもwin2000でも同じsdk1.4.1で試して、動きが異なったことからも、原因はos環境ではないかとまず疑ったのです。さらに新しくわかったのですが、win2000環境でもファイルをアップロードするクライアントが同じwin2000の端末からだと、ファイルが消える現象は起きません。やはり問題はos環境と考えて良いのではと思っています。 また、ファイルの更新時刻で判断する方法ですが、クライアント数が多く頻繁に使われるサーバー上でのプログラムなので、厳密で無い処理は避けたいと思っています。 ともかく、意見交換ができて非常にためになります。ありがとうございます。
- sasadora
- ベストアンサー率68% (59/86)
exists()がtrueを返すのに、InputStreamを作ろうとすると、 FileNotFoundExceptionを返すんですか。 それは難しいですね。 試していないんで分からないんですが、 アップロード中のファイルに対して、 isFile()とか、canRead()とか、length()とかを チェックしてみて、アップロードが完了したファイルと、 相違点があれば、それを基準にできるかも。 あとは、一定時間サイズが増加しなかったら、 アップロードしたとみなすとか。でも、これだと完全じゃないかも 知れませんね。
補足
ヤケになっていろいろ試しましたが、 コピー中のオブジェクトに対して canRead() : true canWrite() : true delete() : true isFile() : true length() : 完全なファイルサイズ(コピー後と同じ) となります。無理っぽいですね。
- a-kuma
- ベストアンサー率50% (1122/2211)
確実に問題を回避できる保証はありませんが、サイズのチェックをしたらどうでしょう。 まず、ファイルを見つけたら、ファイルパスとサイズを保持しておいて、次の監視タイミングで 前回(*)のサイズと同じであれば、コピーが完了しているものとして、処理を行う。 (*) 回線の重さ次第では、監視間隔以内にコピーがされていない可能性もあるので、 二回後、とか、三回後とか調整してみる # ま、こういった処理は General には書けない、ってことでしょうね
補足
回答ありがとうございます。 実はサイズのチェックも試してみたんですが、コピーが始まった時点で完全なファイルとしてのサイズが記録されるようで、コピーしながらファイルサイズが大きくなるというものでは無いようです。(これもOS依存かもしれませんが) 結局ファイルのコピーという部分をOS任せにしている以上、難しいのですね。 それにしても「javaでの例外の発生」-->「os側でのファイルの消去」というwindowsのふるまいは納得いきません。 裏技のようなテクニックでもないものかと。。。
- sasadora
- ベストアンサー率68% (59/86)
いろんな方法があると思いますが、 監視プログラムの方の修正ではなく、 アップロードプログラム(Servlet?)の方の修正になってしまいますが、 アップロードするファイルが作成中の間は、テンポラリなファイルに 書き込んで、アップロード完了後はリネームするような動作にしたら どうでしょうか? 例 アップロード中:file_123456.tmpに書き込み ↓ アップロード完:file_123456.txtにリネーム 監視プログラムは、*.tmpファイルは対象外にして、 アップロードが完了したファイル(*.txt)だけを監視する。
補足
早速の回答ありがとうございます。 アップロードと書きましたが、それは単なるイントラ内でのファイルのコピーです。従ってそこにはアプリケーションは存在しません。つまりどうしても監視側でコピー完了を確認しなければならないんです。 いかがでしょうか?
お礼
お騒がせいたしました。結局XPでは試せなかったのですが、FileInputStreamを取得せずとも、FileクラスのrenameTo()メソドでファイルパスを変えてやることにより、ファイルの移動が可能なことが解りました。(これって常識?) このメソドでは、色々な状況でテストしてみましたが、コピー中のファイルに対して行っても、ファイルが消える、壊れる、といった現象は起きません。 もっともこの場合ファイルのコピーではなく移動なのですが、今回やりたかったことはとりあえずこれで実現できました。 いろいろ試していただいたようなので、報告を兼ねてお礼いたします。では。
補足
貴重な情報ありがとうございます。すぐにXPを用意できないので試してないのですが、他を色々試すうちに新しいことがわかりました。それはファイルをコピーしているクライアントのOSがmacOSだとファイルが消去され、クライアントがwindowsだとおっしゃる通り、FileNotFoundExceptionの後、正常にコピーされるということです。つまりなんらかの形でOS間の互換性の問題があるということでしょうか。 原因がjavaとは関係の無いところにあるのでしょうけど、クライアントをwin系のOSに限定することは出来ないのです。なんとかjava側で回避策が作れないものでしょうか? ちなみに、例外をcatchするブロックではデバグの為にprintStackTrace()を行っている以外何もやっておりません。さらにプログラムのその後の処理を削除しても結果は同じなので他にjavaのプログラムがファイルを消去するようなことは考えられません。