1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.io.file;
19
20 import java.io.IOException;
21 import java.nio.file.FileVisitResult;
22 import java.nio.file.Files;
23 import java.nio.file.LinkOption;
24 import java.nio.file.NoSuchFileException;
25 import java.nio.file.Path;
26 import java.nio.file.attribute.BasicFileAttributes;
27 import java.util.Arrays;
28 import java.util.Objects;
29
30 import org.apache.commons.io.file.Counters.PathCounters;
31
32
33
34
35
36
37 public class DeletingPathVisitor extends CountingPathVisitor {
38
39
40
41
42
43
44 public static DeletingPathVisitor withBigIntegerCounters() {
45 return new DeletingPathVisitor(Counters.bigIntegerPathCounters());
46 }
47
48
49
50
51
52
53 public static DeletingPathVisitor withLongCounters() {
54 return new DeletingPathVisitor(Counters.longPathCounters());
55 }
56
57 private final String[] skip;
58 private final boolean overrideReadOnly;
59 private final LinkOption[] linkOptions;
60
61
62
63
64
65
66
67
68
69 public DeletingPathVisitor(final PathCounters pathCounter, final DeleteOption[] deleteOption, final String... skip) {
70 this(pathCounter, PathUtils.noFollowLinkOptionArray(), deleteOption, skip);
71 }
72
73
74
75
76
77
78
79
80
81
82 public DeletingPathVisitor(final PathCounters pathCounter, final LinkOption[] linkOptions, final DeleteOption[] deleteOption, final String... skip) {
83 super(pathCounter);
84 final String[] temp = skip != null ? skip.clone() : EMPTY_STRING_ARRAY;
85 Arrays.sort(temp);
86 this.skip = temp;
87 this.overrideReadOnly = StandardDeleteOption.overrideReadOnly(deleteOption);
88
89 this.linkOptions = linkOptions == null ? PathUtils.noFollowLinkOptionArray() : linkOptions.clone();
90 }
91
92
93
94
95
96
97
98
99 public DeletingPathVisitor(final PathCounters pathCounter, final String... skip) {
100 this(pathCounter, PathUtils.EMPTY_DELETE_OPTION_ARRAY, skip);
101 }
102
103
104
105
106
107
108
109 private boolean accept(final Path path) {
110 return Arrays.binarySearch(skip, PathUtils.getFileNameString(path)) < 0;
111 }
112
113 @Override
114 public boolean equals(final Object obj) {
115 if (this == obj) {
116 return true;
117 }
118 if (!super.equals(obj)) {
119 return false;
120 }
121 if (getClass() != obj.getClass()) {
122 return false;
123 }
124 final DeletingPathVisitor other = (DeletingPathVisitor) obj;
125 return overrideReadOnly == other.overrideReadOnly && Arrays.equals(skip, other.skip);
126 }
127
128 @Override
129 public int hashCode() {
130 final int prime = 31;
131 int result = super.hashCode();
132 result = prime * result + Arrays.hashCode(skip);
133 result = prime * result + Objects.hash(overrideReadOnly);
134 return result;
135 }
136
137 @Override
138 public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
139 if (PathUtils.isEmptyDirectory(dir)) {
140 Files.deleteIfExists(dir);
141 }
142 return super.postVisitDirectory(dir, exc);
143 }
144
145 @Override
146 public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
147 super.preVisitDirectory(dir, attrs);
148 return accept(dir) ? FileVisitResult.CONTINUE : FileVisitResult.SKIP_SUBTREE;
149 }
150
151 @Override
152 public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
153 if (accept(file)) {
154
155 if (Files.exists(file, linkOptions)) {
156 if (overrideReadOnly) {
157 PathUtils.setReadOnly(file, false, linkOptions);
158 }
159 Files.deleteIfExists(file);
160 }
161
162 if (Files.isSymbolicLink(file)) {
163 try {
164
165 Files.delete(file);
166 } catch (final NoSuchFileException ignored) {
167
168 }
169 }
170 }
171 updateFileCounters(file, attrs);
172 return FileVisitResult.CONTINUE;
173 }
174 }