あなたのディレクトリーを監視しよう

また一週の末ですね~

ジャワ教室の先生は「毎週の宿題はブログ一篇」と言いました、だから今週はまた、ボクはここにいる

ボクは今、そんな難しいプログラムをできないんですから、ちょっと面白いとか、ファンクションがあるプログラムをブログに献上します

今週のテーマはディレクトリーの監視器(Monitor)です

指定したディレクトリーに、どのファイルが削除されたとか、新なファイルを作成とか、あるいは別のファイルをこのディレクトリーにコピーしたとか、これらのファイルの動きをコンソールに表示する。これは、この監視器の機能です

先ずは、考えの筋を説明しよう

このプログラムが、スレッドを使用した。スレッドの「sleep()」方法を使い、一定の時間が経たあと、ディレクトリーの中のファイルを旧ファイルをコンペアマッチしたあと、ファイルの変動がわかる

監視器のクラスに、二つのリスト(List)を作った、名は「list」と「newlist」、毎回、マッチングしたあと、新たのファイルリストを「list」に保存して、スリープのあと、あの時のファイルを「newlist」に保存して、そしてマッチングする。マッチングしたあと、ファイルの変動をコンソールに表示する

コードは、多段で書きます

先ずは、準備のコードはここです:

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class Monitor extends Thread {

	static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	private long sleepTime;
	private File sourceDirectory;
	ArrayList list;// 用于存放旧文件列表
	ArrayList newlist;// 用于存放新文件列表

	public Monitor(File dir, long sleepTime) {
		this.sleepTime = sleepTime;
		sourceDirectory = dir;
		try {
			list = trans(sourceDirectory.listFiles());
		} catch (Exception e) {
			System.out.println("Can't start Monitor!");
		}
	}

	// 把文件数组转换成文件list
	public ArrayList trans(File[] list) {
		ArrayList generateList = new ArrayList();
		try {
			for (int i = 0; i < list.length; i++) {
				generateList.add(list[i]);
			}
		} catch (Exception e) {
		}

		return generateList;

	}
	// 获得文件名以及日期
	public void getInfor(File f) {
		Date d = new Date(System.currentTimeMillis());
		System.out.println(f.getAbsolutePath() + "\n\tTime:" + sdf.format(d));
	}

上のコードには、このクラス必要の変数とリスト、そしてコンストラクターを書きました、「sleepTime」にスレッドの睡眠時間を保存する

「sourceDirectory」に監視するディレクトリーを保存する。そして「list」と「newlist」

プログラムは、ディレクトリーをもらった時、ファイルリストは必要だ、でも、「listFiles()」方法は、リターンしてくれたのはファイルのアレイ(array)です、このクラスに常に使用しているのはリスト(list)だ。そして、「public ArrayList trans(File[] list)」という方法の機能は、アレイをリストにかえる。

ファイルが変動したとき、その変動の時点もアウトプットできるために、この「public void getInfor(File f)」という方法を作った

以上は事前準備です、これからのは本物だ

// 查找文件,返回下表+1
	public int search(File target, ArrayList list) {
		if (target == null)
			return 0;
		for (int i = 1; i <= list.size(); i++) {
			if (list.get(i - 1).equals(target)) {
				return i;
			}
		}

		return 0;
	}

	// 进行新旧文件列表匹配
	public synchronized void matchDirectory(ArrayList f1,
			ArrayList f2) {

		// 输出当前系统时间,表示准备进行一次匹配(不输出也没关系)
		// Date d = new Date(System.currentTimeMillis());
		// System.out.println(sdf.format(d));
		int index = 0;
		for (int i = 0; i < f1.size(); i++) {
			index = search(f1.get(i), f2);
			if (index == 0) {
				System.out.print("Deleted: ");
				getInfor(f1.get(i));
			}
		}
		for (int i = 0; i < f2.size(); i++) {
			index = search(f2.get(i), f1);
			if (index == 0) {
				System.out.print("New File: ");
				getInfor(f2.get(i));
				if (f2.get(i).isDirectory())
					// 当创建了子文件夹时,为子文件夹添加监视器
					new Monitor(f2.get(i), sleepTime).start();
			}
		}

	}


ここで説明します

もし旧リストは「a.txt, b.txt, c.txt」です

新リストは「a.txt, c.txt」です。旧リストのファイルを一つ一つ新リストに検索、もし新リストにいないなら、このファイルが削除されたとこが分かる

旧リストのa.txtで新リストに検索、結果は1(アレイインデックス+1)、ここに、もし新リストにないなら、0をリターンです、だからa.txtの検索の結果は1

旧リストのb.txtで新リストに検索、結果は0、だから、b.txtが削除された、c.txtは同じです

逆に、もし旧リストは「1.txt, 3.txt, 4.txt」、新リストには「1.txt, 2.txt, 3.txt, 4.txt」新リストのファイルを一つ一つ旧リストに検索

新リストにの「2.txt」は旧リストにない、だから、「2.txt」は新たなファイルです。だから、「matchDirectory」方法には、旧・新、二回の検索がある

こうやって、ディレクトリーの変動が分かる

ちょっと注意するのは、もし新たのディレクトリーを探知したら、そのディレクトリーに同じ監視器を仕掛ける、これはなぜですか、後に説明します

最後は、スレッドの「Run()」方法です

	@Override
	public void run() {
		if (!sourceDirectory.isDirectory()) {
		} else {
			while (true) {
				// 检测被监视文件夹是否被删除,如果被删除,自动关闭该文件夹的监视器
				if (!sourceDirectory.exists()) {
					break;
				}

				newlist = trans(sourceDirectory.listFiles());
				matchDirectory(list, newlist);
				list = (ArrayList) newlist.clone();

				try {
					sleep(sleepTime);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

「Run()」に、無限ループで、この監視器を動かし続ける、つまり、人がこのプログラムを停止しないなら、かつ、異常がないなら、旧、新リストのマッチングはずっとし続く。このループに、毎回、新リストのデータを旧リストに移動する、そして、この旧リストは、次のループの新リストとマッチングする。そう繰り返して、監視の効果ができる。

ここにも、注意点がある。もし、この監視されているディレクトリーが削除されたら、「break」で、この無限ループを脱出する、こうやって、システム資源を無駄に使用しない

本来、このプログラムはここまででした が

昨日、少し思い溢れた。

この監視器は、一つのディレクトリーしか、監視できません、そして、中のサブディレクトリーも監視できません。だから、「起動すれば、このディレクトリーの全てのサブディレクトリーも監視できるかな」と思いました

そして、「再帰(recurse)」の思想で、この完全監視をできた!

コードはここです

package assignment;

import java.io.File;

public class TotalMonitor extends Thread {

	private long sleepTime;

	public TotalMonitor(long sleepTime) {
		this.sleepTime = sleepTime;
	}

	// 递归启动监视器
	public void startMonitor(File sourceDirectory) {
		new Monitor(sourceDirectory, sleepTime).start();
		File[] list = sourceDirectory.listFiles();
		for (File f : list) {
			if (f.isDirectory()) {
				startMonitor(f);
			}
		}
	}

	@Override
	public void run() {
		while (true) {
			// 显示当前监控文件夹数量
			System.out.println("Active Threads: " + activeCount());
			System.gc();
			try {
				sleep(sleepTime);
			} catch (InterruptedException e) {
			}
		}
	}

	public static void main(String[] args) {
		File f = new File("e:");
		TotalMonitor TM = new TotalMonitor(5000);
		TM.startMonitor(f);
		TM.start();
	}
}


ちなみに、この二つのクラスは同じパッケージです

皆さん、ディレクトリーのトラバーサル(directory traversal)が知っているでしょう、ディレクトリーにディレクトリーを探知したら、そのサブディレクトリーをトラバーサルする

これもおなじ、このクラスの「startMonitor()」方法は、ディレクトリーのトラバーサルと同様で、違うのは、もしディレクトリーを探知したら、上の監視器(Monitor)を仕掛ける、つまり、このクラスは本当の監視器ではない、ただ起動するとき、全てのディレクトリーを監視器仕掛けするだけです。監視器のクラスはスレッドを引き継ぐから、毎の監視器は別々で、互いに邪魔をしません

では、現在、前に言ったの 「監視器は新たのディレクトリーを探知したら、監視器はを仕掛ける」の原因はこれです、つまり、元の監視器は、その二行のコードは要らないです、でも、全てのディレクトリーを監視するために、すなわち、監視器を起動させたあと、新たのディレクトリーも監視できるために、その二行のコードは必要です。それは、ここの目的とつながっている。

監視器の停止も同じだ、もし監視器は目標(directory)を探知できないなら、その目標の監視器は自動停止機能を備えている


このプログラムはただ授業の宿題の一つで、ボクは前にもっと機能を広げて、このプログラムをできた が

このプログラムには、多数の不具合があると知っている、たとえ、ファイルの再命名が探知できない、このプログラムでの表現は削除された、そして名が違うファイルができた、実は同じファイルです。恥ずかしいけど、ボクは今、この不具合を修正できません。

だから今、ボクは頑張って、もっと勉強して、いつかこの不具合を修正できるようになっていく


では、今週のブログはここです、ご覧くださってありがとうございます~


你可能感兴趣的:(日本語練習)