LoginSignup
14
15

More than 3 years have passed since last update.

メモ : 【Java】監視しているディレクトリにファイルが入ったら処理を行う

Last updated at Posted at 2018-07-19

背景

前回、CSVファイルを加工して出力するというのを書いたんですが、
対象のディレクトリにCSVファイルが入ってきたらファイルを加工するっていう流れにしたいなー
と思ったので、コードを書き残します。

監視.png

まずはディレクトリの監視

- WatchService 使い方メモ
- Javaでファイルが作成されるのを待って、作成を検知してから次の処理を行う
:grinning: こちらのページを参考にさせて頂きました。ありがとうございます。

test.java
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.Watchable;

import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.WatchEvent.*;

public class test {

    public static void main(String[] args) throws Exception {
        Path dir = Paths.get("C://develop//BOX");
        WatchService watcher = FileSystems.getDefault().newWatchService();
        dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);

        for (;;) {
            WatchKey watchKey = watcher.take();
            for (WatchEvent<?> event: watchKey.pollEvents()) {
                if (event.kind() == OVERFLOW) continue;

                WatchEvent<Path> ev = cast(event);
                Path name = ev.context();
                Path child = dir.resolve(name);
                System.out.format("%s: %s\n", event.kind().name(), child);
            }
            watchKey.reset();
        }
    }

    @SuppressWarnings("unchecked")
    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>)event;
    }
}

では、C:\developBOX というディレクトリを作成して、
1.png

任意の場所で test.java をコンパイルしてクラスを実行してみます。( ※ 今回ワタシは D:\で実行してます)
2.png

わーっ!コンパイル時にエラーが出ちゃったよって方は :beginner:こちら 参考になります。

では、classファイルを実行します。適当なファイルをBOXディレクトリに入れてみます。
3.png

おーっ‼ディレクトリに入れた さんぷる.txt が
ENTRY_CREATE(作成) と ENTRY_MODIFY(変更) と表示されました。
4.png

ファイルをディレクトリから削除するとENTRY_DELETE(削除)が表示されています。
5.png

実際動かしてからの方がわかるなーと思うので先に動かした時の画像貼りましたが
test.javaにはこんなのが書いてます。(コメントはワタシの解釈で書いてるので間違えてるかも…。)
2行目の WatchService watcher = FileSystems.getDefault().newWatchService(); というのは
決まった言い回しらしいので深く考えずそのまま使います。

Path dir = Paths.get("C://develop//BOX");                            //"dir"に監視対象のディレクトリを指定して
WatchService watcher = FileSystems.getDefault().newWatchService();   //WatchServiceを"watcher"という名前で作成
dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);     //"dir"内で監視するイベントを指定(作成,削除,変更)
for (;;) {                                                           //イベントを待機するために無限ループを実装
   WatchKey watchKey = watcher.take();                               //watcherから監視キー"watchKey"を取得する
   for (WatchEvent<?> event: watchKey.pollEvents()) {                //pollEventsメソッドでWatchEventが格納されたListが取得出来る。
       if (event.kind() == OVERFLOW) continue;                       //"OVERFLOW"はイベントが消失or破棄されたのを示す特殊な監視イベント

        WatchEvent<Path> ev = cast(event);
        Path name = ev.context();                                    //"name"にイベント・コンテキストで取得してファイル名を設定       
        Path child = dir.resolve(name);                              //resolveメソッドでフルパス("dir"のパスに"name"を追加したもの)を設定
        System.out.format("%s: %s\n", event.kind().name(), child);   //出力時は【イベント名:ファイルのフルパス】で出力する指示
   }
   watchKey.reset();                                                 //監視キーをリセットする(WatchKeyの状態をREADYに戻すため)

csvを加工する処理を組み合わせます

前回のコード [ 読み込んだcsvを加工(条件で抽出、変更)して出力する ]
test.java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class test{

    public static void main(String[] args) {
        process("20180712.csv",  ":00,","output.csv");
    }

    public static void process(String read_file, String searchString, String output_file){

        try(FileReader fr = new FileReader(read_file);BufferedReader br = new BufferedReader(fr);
            FileWriter fw = new FileWriter(output_file);BufferedWriter bw = new BufferedWriter(fw)){

            String line;
            while ((line = br.readLine()) != null) {
                Pattern p = Pattern.compile(searchString);
                Matcher m = p.matcher(line);
                if (m.find()){
                    String[] csvArray;
                    csvArray = line.split(",");
                    String time  = csvArray[0];
                    float press = Float.parseFloat(csvArray[1])%10000;
                    String pressure = String.format("%.2f", press);
                    String temperature  = csvArray[2];
                    String outputLine = String.join(",",time,pressure,temperature);
                    bw.write(outputLine);
                    bw.newLine();
                }else{ 
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

前回のコードと上で書いたコードは大きく変えてません。ほぼ結合しただけです。

test.java
import java.nio.file.FileSystems;      //ディレクトリ監視に必要
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.Watchable;
import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.WatchEvent.*;

import java.io.BufferedReader;        //csvを加工して出力するのに必要
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class test {

    public static void main(String[] args) throws Exception {

        Path dir = Paths.get(System.getenv("CSV_DIR"));       //今回は 監視するディレクトリを環境変数"CSV_DIR"に設定
        WatchService watcher = FileSystems.getDefault().newWatchService();
        dir.register(watcher, ENTRY_CREATE);                  //今回は ENTRY_CREATEだけ検知すればOK

        for (;;) {
            WatchKey watchKey = watcher.take();
            for (WatchEvent<?> event: watchKey.pollEvents()) {
                if (event.kind() == OVERFLOW) continue;              
                WatchEvent<Path> ev = cast(event);
                Path name = ev.context();
                Path child = dir.resolve(name);
                String newfile =String.format("%s", child);

                process(newfile, ":00,","D://tedkuma//★"+name); //processで読込むファイルに検知したファイルのフルパスを渡す
                System.out.println("Output success:"+name);
            }
            watchKey.reset();
        }  
    }

    @SuppressWarnings("unchecked")
    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>)event;
    }

    public static void process(String read_file, String searchString, String output_file){ //以下は前回のをそのまま流用

        try(FileReader fr = new FileReader(read_file);BufferedReader br = new BufferedReader(fr);
            FileWriter fw = new FileWriter(output_file);BufferedWriter bw = new BufferedWriter(fw)){

            String line;
            while ((line = br.readLine()) != null) {
                Pattern p = Pattern.compile(searchString);
                Matcher m = p.matcher(line);
                if (m.find()){
                    String[] csvArray;
                    csvArray = line.split(",");
                    String time  = csvArray[0];
                    float press = Float.parseFloat(csvArray[1])%10000;
                    String pressure = String.format("%.2f", press);
                    String temperature  = csvArray[2];
                    String outputLine = String.join(",",time,pressure,temperature);
                    bw.write(outputLine);
                    bw.newLine();
                }else{ 
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

日本語のコメントとか★マークとかがjavaファイルの中に含まれているので
javacだけではコンパイルエラーになってしまいます :sweat:
:skull: エラー:  この文字は、エンコーディングMS932にマップできません って出てしまうので、
今回は javac -encodhing utf-8 test.java でコンパイルしています。では、実行してみます。
11.png

環境変数"CSV_DIR"は C:\develop\monitored という場所に設定しました。(今回の監視対象ディレクトリ)
この中に加工したいCSVファイルを入れてみます。
12.png

Output success:の後ろにディレクトリに入れたファイル名が表示されています。
13.png

出力先に指定したDドライブのtedkumaディレクトリを確認してみます。
ファイル名の頭に★が付いたファイルが出力されて、中のcsvも加工されています。
14.png

今回は以上です。

14
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15