- PR -

大量のファイルのなかから更新・追加されたファイルを取得するには?

1
投稿者投稿内容
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-09-11 10:37
こんにちは。いつもお世話になってます。

今、Javaで自動転送機能付きFTPクライアントを作っています。
で、ローカルディスクの指定されたフォルダ内を定期的にスキャンして、変更や追加が
あったものをFTPサーバへ転送する機能を持っています。

現在の変更・追加の判断はフォルダ内のファイル一覧を取得して、その更新日時をメモリ
内に保持します。次回スキャン時に、同様にファイル一覧と更新日時を比較して、変化が
あったものを転送対象のファイルとしています。

ローカルディスクなら数百個のファイルでも、この方法でも一瞬で処理できます。
しかし、ローカルドライブをネットワークドライブ経由にしてみると、やはりファイル一覧
や更新日時の取得はとてつもなく遅いです。

このように大量のファイルの中から更新・追加されたファイルのファイル名を取得するには、
何かよい方法はありますか?

Windowsなら定期スキャンしなくても、メッセージを監視すればファイルの更新・追加した
タイミングを取得できると聞いたのですが、Javaでそれに近いことはできるのでしょうか?
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-09-11 15:40
小手先です。こんな方法でうまくいくかどうかは分かりません。

指定したディレクトリ内において、前回アクセスしたときの全ファイル名と更新日時はわかっているものとします。ファイル名と更新日時のマップを作成し、ファイルリスト取得時にこのマップを参照し、更新日時が違うファイルまたは、前回存在していなかったファイルのみを返させるようにします。

取得後はこのマップを必ず更新しておきます。

実装例として、

コード:
class ModifiedFileFilter implements FileFilter {
  /** Map<File, Long> */
  private Map mModifiedMap;

  public ModifiedFileFilter(Map inMap) {
    mModifiedMap = inMap;
  }

  public boolean accept(File inFile) {
    Long aModifiedTime = (Long)mModifiedMap.get(inFile)
    
    if (null== aModifiedTime) return true;

    return (aModifiedTime.longValue() != inFile.lastModified()); 
  }
}

File aDir = new File(....);
File[] aModifiedFile = aDir.listFiles(new ModifiedFileFilter(.....));




maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-09-11 17:06
返答ありがとうございます。

しかし、同じような考え方でやってはみているのですが、Javaの限界か期待するパフォー
マンスが出ませんでした。で、さらに細かく調べました。

もう少し具体的に言うと、Win32のAPIの場合は、FindFirstFileやFindNextFileを使えば
一発でWIN32_FIND_DATA構造体にファイル属性が入り、ファイル件数分ループします。
3000個ほどのファイルをループでまわしても、ネットワークドライブ経由でも環境にもより
ますが、1秒程度で値が取れました。

しかし、Javaの場合は、File#listFile()でファイルの列挙配列を取得してその配列分を
ループでまわし、その中でFile#lastModifiedやFile#length()をコールすると、その都度
属性取得のAPIをコールしているようで、ローカルディスクならいいのですが、ネットワーク
ドライブで3000個ほどのファイルがあった場合、都度ネットワーク経由で属性を取得して
いるため、めちゃくちゃ遅いのです。上記のWinのAPIでは1秒程度の処理がjavaでは120秒
くらいかかっています。

ようするに、大量の件数分のファイル情報をネットワークドライブ経由で取得する部分が
ボトルネックになっているようです。

また、WinのAPIでReadDirectoryChangesWを使えばファイルが追加・更新されたイベント
と対象ファイル名を取れるようですが、WinNT系のAPIでした。
Win9X系では、ファイルが更新・追加のイベントを取れるようですが、「どのファイルが」
というのは取れないようです。結局、比較チェックを自力でやらないといけないようです。
したがって、Javaでもファイルの更新監視を行う機能はないでしょうね。

結局、ファイル情報取得の部分をCでつくり、定期的にJavaでコールして情報取得して、
Javaで更新・追加の有無をチェックするようにしました。
お騒がせしました。ありがとうございました。
ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-09-11 17:12
ども、ほむらです。
OS依存ですが。。。。
------------------
lsコマンドとか dirコマンドで一覧の出力内容をバッファにとりこんで
検索させるという手もあります。

まぁ参考までに

1

スキルアップ/キャリアアップ(JOB@IT)