/** * Copyright 2007 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.paoding.analysis.dictionary.support.detection; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; /** * * @author Zhiliang Wang [qieqie.wang@gmail.com] * * @since 2.0.2 * */ public class Snapshot { // 此次快照版本,使用时间表示 private long version; // 根地址,绝对地址,使用/作为目录分隔符 private String root; // String为相对根的地址,使用/作为目录分隔符 private Map/*<String, InnerNode>*/ nodesMap = new HashMap/*<String, InnerNode>*/(); // private InnerNode[] nodes; private Snapshot() { } public static Snapshot flash(String root, FileFilter filter) { return flash(new File(root), filter); } public static Snapshot flash(File rootFile, FileFilter filter) { Snapshot snapshot = new Snapshot(); snapshot.implFlash(rootFile, filter); return snapshot; } private void implFlash(File rootFile, FileFilter filter) { version = System.currentTimeMillis(); root = rootFile.getAbsolutePath().replace('\\', '/'); if (!rootFile.exists()) { // do nothing, maybe the file has been deleted nodes = new InnerNode[0]; } else { InnerNode rootNode = new InnerNode(); rootNode.path = root; rootNode.isFile = rootFile.isFile(); rootNode.lastModified = rootFile.lastModified(); nodesMap.put(root, rootNode); if (rootFile.isDirectory()) { LinkedList/*<File>*/ files = getPosterity(rootFile, filter); nodes = new InnerNode[files.size()]; Iterator/*<File>*/ iter = files.iterator(); for (int i = 0; i < nodes.length; i++) { File f = (File) iter.next(); String path = f.getAbsolutePath().substring( this.root.length() + 1); path = path.replace('\\', '/'); InnerNode node = new InnerNode(); node.path = path; node.isFile = f.isFile(); node.lastModified = f.lastModified(); int index = path.lastIndexOf('/'); node.parent = index == -1 ? root : path.substring(0, index); nodes[i] = node; nodesMap.put(path, node); } } } } public long getVersion() { return version; } public void setVersion(long version) { this.version = version; } public String getRoot() { return root; } public void setRoot(String root) { this.root = root; } public Difference diff(Snapshot that) { Snapshot older = that; Snapshot younger = this; if (that.version > this.version) { older = this; younger = that; } Difference diff = new Difference(); if (!younger.root.equals(older.root)) { throw new IllegalArgumentException("the snaps should be same root"); } for (int i = 0; i < older.nodes.length; i ++) { InnerNode olderNode = older.nodes[i]; InnerNode yongerNode = (InnerNode) younger.nodesMap.get((String) olderNode.path); if (yongerNode == null) { diff.getDeleted().add(olderNode); } else if (yongerNode.lastModified != olderNode.lastModified) { diff.getModified().add(olderNode); } } for (int i = 0; i < younger.nodes.length; i ++) { InnerNode yongerNode = younger.nodes[i]; InnerNode olderNode = (InnerNode) older.nodesMap.get((String) yongerNode.path); if (olderNode == null) { diff.getNewcome().add(yongerNode); } } diff.setOlder(older); diff.setYounger(younger); return diff; } public static void main(String[] args) throws InterruptedException { File f = new File("dic"); Snapshot snapshot1 = Snapshot.flash(f, null); System.out.println("----"); Thread.sleep(3000); System.out.println("----"); Thread.sleep(3000); System.out.println("----"); Snapshot snapshot2 = Snapshot.flash(f, null); Difference diff = snapshot2.diff(snapshot1); String deleted = ArraysToString(diff.getDeleted().toArray( new Node[] {})); System.out.println("deleted: " + deleted); String modified = ArraysToString(diff.getModified().toArray( new Node[] {})); System.out.println("modified: " + modified); String newcome = ArraysToString(diff.getNewcome().toArray( new Node[] {})); System.out.println("newcome: " + newcome); } // 低于JDK1.5无Arrays.toString()方法,故有以下方法 private static String ArraysToString(Object[] a) { if (a == null) return "null"; int iMax = a.length - 1; if (iMax == -1) return "[]"; StringBuffer b = new StringBuffer(); b.append('['); for (int i = 0;; i++) { b.append(String.valueOf(a[i])); if (i == iMax) return b.append(']').toString(); b.append(", "); } } // -------------------------------------------- private LinkedList/*<File>*/ getPosterity(File root, FileFilter filter) { ArrayList/*<File>*/ dirs = new ArrayList/*<File>*/(); LinkedList/*<File>*/ files = new LinkedList/*<File>*/(); dirs.add(root); int index = 0; while (index < dirs.size()) { File cur = (File) dirs.get(index++); File[] children = cur.listFiles(); for (int i = 0; i < children.length; i ++) { File f = children[i]; if (filter == null || filter.accept(f)) { if (f.isDirectory()) { dirs.add(f); } else { files.add(f); } } } } return files; } class InnerNode extends Node { String parent; long lastModified; } }