001/* 002 * (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bstefanescu 018 */ 019package org.nuxeo.common.utils; 020 021import java.io.File; 022import java.io.FileFilter; 023import java.util.Iterator; 024import java.util.LinkedList; 025import java.util.NoSuchElementException; 026import java.util.Queue; 027 028/** 029 * @author <a href="mailto:[email protected]">Bogdan Stefanescu</a> 030 */ 031public class FileTreeIterator implements Iterator<File> { 032 033 private final Queue<Iterator<File>> queue = new LinkedList<>(); 034 035 private File file; // last iterated file 036 037 private FileFilter filter; 038 039 public FileTreeIterator(File root) { 040 queue.add(new OneFileIterator(root)); 041 } 042 043 public FileTreeIterator(File root, boolean excludeRoot) { 044 if (excludeRoot) { 045 queue.add(new LazyChildrenIterator(root)); 046 } else { 047 queue.add(new OneFileIterator(root)); 048 } 049 } 050 051 public void setFilter(FileFilter filter) { 052 this.filter = filter; 053 } 054 055 public FileFilter getFilter() { 056 return filter; 057 } 058 059 public boolean hasNext() { 060 if (queue.isEmpty()) { 061 return false; 062 } 063 Iterator<File> it = queue.peek(); 064 if (it.hasNext()) { 065 return true; 066 } else { 067 queue.poll(); 068 return hasNext(); 069 } 070 } 071 072 public File next() { 073 if (!hasNext()) { 074 throw new NoSuchElementException("No more files to iterate over"); 075 } 076 file = queue.peek().next(); 077 if (file.isDirectory()) { 078 queue.add(new LazyChildrenIterator(file)); 079 } 080 return file; 081 } 082 083 public void remove() { 084 if (file == null) { 085 throw new IllegalStateException("there is no current file to delete"); 086 } 087 org.apache.commons.io.FileUtils.deleteQuietly(file); 088 } 089 090 // we don't fulfill iterator contract - we don't need a real iterator, 091 // this is used only internally 092 private static class OneFileIterator implements Iterator<File> { 093 094 private File file; 095 096 private OneFileIterator(File file) { 097 this.file = file; 098 } 099 100 public boolean hasNext() { 101 return file != null; 102 } 103 104 public File next() { 105 File next = file; 106 file = null; 107 return next; 108 } 109 110 public void remove() { 111 throw new UnsupportedOperationException("remove not supported"); 112 } 113 } 114 115 // we don't fulfill iterator contract - we don't need a real iterator, 116 // this is used only internally 117 private class LazyChildrenIterator implements Iterator<File> { 118 119 private final File dir; 120 121 private File[] children; 122 123 private int pos = -1; // last pos 124 125 private LazyChildrenIterator(File dir) { 126 this.dir = dir; 127 } 128 129 public boolean hasNext() { 130 if (children == null) { 131 children = filter == null ? dir.listFiles() : dir.listFiles(filter); 132 if (children == null) { 133 return false; // not a dir 134 } 135 return children.length > 0; 136 } else { 137 return pos < children.length - 1; 138 } 139 } 140 141 public File next() { 142 return children[++pos]; 143 } 144 145 public void remove() { 146 throw new UnsupportedOperationException("remove not supported"); 147 } 148 } 149 150 public static void main(String[] args) { 151 FileTreeIterator it = new FileTreeIterator(new File("/root/kits"), false); 152 while (it.hasNext()) { 153 System.out.println(">> " + it.next()); 154 } 155 } 156 157}