📄 directorywalker.java
字号:
//-----------------------------------------------------------------------
/**
* Internal method that walks the directory hierarchy in a depth-first manner.
* <p>
* Users of this class do not need to call this method. This method will
* be called automatically by another (public) method on the specific subclass.
* <p>
* Writers of subclasses should call this method to start the directory walk.
* Once called, this method will emit events as it walks the hierarchy.
* The event methods have the prefix <code>handle</code>.
*
* @param startDirectory the directory to start from, not null
* @param results the collection of result objects, may be updated
* @throws NullPointerException if the start directory is null
* @throws IOException if an I/O Error occurs
*/
protected final void walk(File startDirectory, Collection results) throws IOException {
if (startDirectory == null) {
throw new NullPointerException("Start Directory is null");
}
try {
handleStart(startDirectory, results);
walk(startDirectory, 0, results);
handleEnd(results);
} catch(CancelException cancel) {
handleCancelled(startDirectory, results, cancel);
}
}
/**
* Main recursive method to examine the directory hierarchy.
*
* @param directory the directory to examine, not null
* @param depth the directory level (starting directory = 0)
* @param results the collection of result objects, may be updated
* @throws IOException if an I/O Error occurs
*/
private void walk(File directory, int depth, Collection results) throws IOException {
checkIfCancelled(directory, depth, results);
if (handleDirectory(directory, depth, results)) {
handleDirectoryStart(directory, depth, results);
int childDepth = depth + 1;
if (depthLimit < 0 || childDepth <= depthLimit) {
checkIfCancelled(directory, depth, results);
File[] childFiles = (filter == null ? directory.listFiles() : directory.listFiles(filter));
if (childFiles == null) {
handleRestricted(directory, childDepth, results);
} else {
for (int i = 0; i < childFiles.length; i++) {
File childFile = childFiles[i];
if (childFile.isDirectory()) {
walk(childFile, childDepth, results);
} else {
checkIfCancelled(childFile, childDepth, results);
handleFile(childFile, childDepth, results);
checkIfCancelled(childFile, childDepth, results);
}
}
}
}
handleDirectoryEnd(directory, depth, results);
}
checkIfCancelled(directory, depth, results);
}
//-----------------------------------------------------------------------
/**
* Checks whether the walk has been cancelled by calling {@link #handleIsCancelled},
* throwing a <code>CancelException</code> if it has.
* <p>
* Writers of subclasses should not normally call this method as it is called
* automatically by the walk of the tree. However, sometimes a single method,
* typically {@link #handleFile}, may take a long time to run. In that case,
* you may wish to check for cancellation by calling this method.
*
* @param file the current file being processed
* @param depth the current file level (starting directory = 0)
* @param results the collection of result objects, may be updated
* @throws IOException if an I/O Error occurs
*/
protected final void checkIfCancelled(File file, int depth, Collection results) throws IOException {
if (handleIsCancelled(file, depth, results)) {
throw new CancelException(file, depth);
}
}
/**
* Overridable callback method invoked to determine if the entire walk
* operation should be immediately cancelled.
* <p>
* This method should be implemented by those subclasses that want to
* provide a public <code>cancel()</code> method available from another
* thread. The design pattern for the subclass should be as follows:
* <pre>
* public class FooDirectoryWalker extends DirectoryWalker {
* private volatile boolean cancelled = false;
*
* public void cancel() {
* cancelled = true;
* }
* private void handleIsCancelled(File file, int depth, Collection results) {
* return cancelled;
* }
* protected void handleCancelled(File startDirectory,
* Collection results, CancelException cancel) {
* // implement processing required when a cancellation occurs
* }
* }
* </pre>
* <p>
* If this method returns true, then the directory walk is immediately
* cancelled. The next callback method will be {@link #handleCancelled}.
* <p>
* This implementation returns false.
*
* @param file the file or directory being processed
* @param depth the current directory level (starting directory = 0)
* @param results the collection of result objects, may be updated
* @return true if the walk has been cancelled
* @throws IOException if an I/O Error occurs
*/
protected boolean handleIsCancelled(
File file, int depth, Collection results) throws IOException {
// do nothing - overridable by subclass
return false; // not cancelled
}
/**
* Overridable callback method invoked when the operation is cancelled.
* The file being processed when the cancellation occurred can be
* obtained from the exception.
* <p>
* This implementation just re-throws the {@link CancelException}.
*
* @param startDirectory the directory that the walk started from
* @param results the collection of result objects, may be updated
* @param cancel the exception throw to cancel further processing
* containing details at the point of cancellation.
* @throws IOException if an I/O Error occurs
*/
protected void handleCancelled(File startDirectory, Collection results,
CancelException cancel) throws IOException {
// re-throw exception - overridable by subclass
throw cancel;
}
//-----------------------------------------------------------------------
/**
* Overridable callback method invoked at the start of processing.
* <p>
* This implementation does nothing.
*
* @param startDirectory the directory to start from
* @param results the collection of result objects, may be updated
* @throws IOException if an I/O Error occurs
*/
protected void handleStart(File startDirectory, Collection results) throws IOException {
// do nothing - overridable by subclass
}
/**
* Overridable callback method invoked to determine if a directory should be processed.
* <p>
* This method returns a boolean to indicate if the directory should be examined or not.
* If you return false, the entire directory and any subdirectories will be skipped.
* Note that this functionality is in addition to the filtering by file filter.
* <p>
* This implementation does nothing and returns true.
*
* @param directory the current directory being processed
* @param depth the current directory level (starting directory = 0)
* @param results the collection of result objects, may be updated
* @return true to process this directory, false to skip this directory
* @throws IOException if an I/O Error occurs
*/
protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
// do nothing - overridable by subclass
return true; // process directory
}
/**
* Overridable callback method invoked at the start of processing each directory.
* <p>
* This implementation does nothing.
*
* @param directory the current directory being processed
* @param depth the current directory level (starting directory = 0)
* @param results the collection of result objects, may be updated
* @throws IOException if an I/O Error occurs
*/
protected void handleDirectoryStart(File directory, int depth, Collection results) throws IOException {
// do nothing - overridable by subclass
}
/**
* Overridable callback method invoked for each (non-directory) file.
* <p>
* This implementation does nothing.
*
* @param file the current file being processed
* @param depth the current directory level (starting directory = 0)
* @param results the collection of result objects, may be updated
* @throws IOException if an I/O Error occurs
*/
protected void handleFile(File file, int depth, Collection results) throws IOException {
// do nothing - overridable by subclass
}
/**
* Overridable callback method invoked for each restricted directory.
* <p>
* This implementation does nothing.
*
* @param directory the restricted directory
* @param depth the current directory level (starting directory = 0)
* @param results the collection of result objects, may be updated
* @throws IOException if an I/O Error occurs
*/
protected void handleRestricted(File directory, int depth, Collection results) throws IOException {
// do nothing - overridable by subclass
}
/**
* Overridable callback method invoked at the end of processing each directory.
* <p>
* This implementation does nothing.
*
* @param directory the directory being processed
* @param depth the current directory level (starting directory = 0)
* @param results the collection of result objects, may be updated
* @throws IOException if an I/O Error occurs
*/
protected void handleDirectoryEnd(File directory, int depth, Collection results) throws IOException {
// do nothing - overridable by subclass
}
/**
* Overridable callback method invoked at the end of processing.
* <p>
* This implementation does nothing.
*
* @param results the collection of result objects, may be updated
* @throws IOException if an I/O Error occurs
*/
protected void handleEnd(Collection results) throws IOException {
// do nothing - overridable by subclass
}
//-----------------------------------------------------------------------
/**
* CancelException is thrown in DirectoryWalker to cancel the current
* processing.
*/
public static class CancelException extends IOException {
/** Serialization id. */
private static final long serialVersionUID = 1347339620135041008L;
/** The file being processed when the exception was thrown. */
private File file;
/** The file depth when the exception was thrown. */
private int depth = -1;
/**
* Constructs a <code>CancelException</code> with
* the file and depth when cancellation occurred.
*
* @param file the file when the operation was cancelled, may be null
* @param depth the depth when the operation was cancelled, may be null
*/
public CancelException(File file, int depth) {
this("Operation Cancelled", file, depth);
}
/**
* Constructs a <code>CancelException</code> with
* an appropriate message and the file and depth when
* cancellation occurred.
*
* @param message the detail message
* @param file the file when the operation was cancelled
* @param depth the depth when the operation was cancelled
*/
public CancelException(String message, File file, int depth) {
super(message);
this.file = file;
this.depth = depth;
}
/**
* Return the file when the operation was cancelled.
*
* @return the file when the operation was cancelled
*/
public File getFile() {
return file;
}
/**
* Return the depth when the operation was cancelled.
*
* @return the depth when the operation was cancelled
*/
public int getDepth() {
return depth;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -