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:bs@nuxeo.com">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 @Override 060 public boolean hasNext() { 061 if (queue.isEmpty()) { 062 return false; 063 } 064 Iterator<File> it = queue.peek(); 065 if (it.hasNext()) { 066 return true; 067 } else { 068 queue.poll(); 069 return hasNext(); 070 } 071 } 072 073 @Override 074 public File next() { 075 if (!hasNext()) { 076 throw new NoSuchElementException("No more files to iterate over"); 077 } 078 file = queue.peek().next(); 079 if (file.isDirectory()) { 080 queue.add(new LazyChildrenIterator(file)); 081 } 082 return file; 083 } 084 085 @Override 086 public void remove() { 087 if (file == null) { 088 throw new IllegalStateException("there is no current file to delete"); 089 } 090 org.apache.commons.io.FileUtils.deleteQuietly(file); 091 } 092 093 // we don't fulfill iterator contract - we don't need a real iterator, 094 // this is used only internally 095 private static class OneFileIterator implements Iterator<File> { 096 097 private File file; 098 099 private OneFileIterator(File file) { 100 this.file = file; 101 } 102 103 @Override 104 public boolean hasNext() { 105 return file != null; 106 } 107 108 @Override 109 public File next() { 110 if (!hasNext()) { 111 throw new NoSuchElementException(); 112 } 113 File next = file; 114 file = null; 115 return next; 116 } 117 118 @Override 119 public void remove() { 120 throw new UnsupportedOperationException("remove not supported"); 121 } 122 } 123 124 // we don't fulfill iterator contract - we don't need a real iterator, 125 // this is used only internally 126 private class LazyChildrenIterator implements Iterator<File> { 127 128 private final File dir; 129 130 private File[] children; 131 132 private int pos = -1; // last pos 133 134 private LazyChildrenIterator(File dir) { 135 this.dir = dir; 136 } 137 138 @Override 139 public boolean hasNext() { 140 if (children == null) { 141 children = filter == null ? dir.listFiles() : dir.listFiles(filter); 142 if (children == null) { 143 return false; // not a dir 144 } 145 return children.length > 0; 146 } else { 147 return pos < children.length - 1; 148 } 149 } 150 151 @Override 152 public File next() { 153 if (!hasNext()) { 154 throw new NoSuchElementException(); 155 } 156 return children[++pos]; 157 } 158 159 @Override 160 public void remove() { 161 throw new UnsupportedOperationException("remove not supported"); 162 } 163 } 164 165 public static void main(String[] args) { 166 FileTreeIterator it = new FileTreeIterator(new File("/root/kits"), false); 167 while (it.hasNext()) { 168 System.out.println(">> " + it.next()); 169 } 170 } 171 172}