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 public DeletingPathVisitor(final PathCounters pathCounter, final String... skip) {
99 this(pathCounter, PathUtils.EMPTY_DELETE_OPTION_ARRAY, skip);
100 }
101
102
103
104
105
106
107
108 private boolean accept(final Path path) {
109 return Arrays.binarySearch(skip, PathUtils.getFileNameString(path)) < 0;
110 }
111
112 @Override
113 public boolean equals(final Object obj) {
114 if (this == obj) {
115 return true;
116 }
117 if (!super.equals(obj)) {
118 return false;
119 }
120 if (getClass() != obj.getClass()) {
121 return false;
122 }
123 final DeletingPathVisitor other = (DeletingPathVisitor) obj;
124 return overrideReadOnly == other.overrideReadOnly && Arrays.equals(skip, other.skip);
125 }
126
127 @Override
128 public int hashCode() {
129 final int prime = 31;
130 int result = super.hashCode();
131 result = prime * result + Arrays.hashCode(skip);
132 result = prime * result + Objects.hash(overrideReadOnly);
133 return result;
134 }
135
136 @Override
137 public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
138 if (PathUtils.isEmptyDirectory(dir)) {
139 Files.deleteIfExists(dir);
140 }
141 return super.postVisitDirectory(dir, exc);
142 }
143
144 @Override
145 public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
146 super.preVisitDirectory(dir, attrs);
147 return accept(dir) ? FileVisitResult.CONTINUE : FileVisitResult.SKIP_SUBTREE;
148 }
149
150 @Override
151 public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
152 if (accept(file)) {
153
154 if (Files.exists(file, linkOptions)) {
155 if (overrideReadOnly) {
156 PathUtils.setReadOnly(file, false, linkOptions);
157 }
158 Files.deleteIfExists(file);
159 }
160
161 if (Files.isSymbolicLink(file)) {
162 try {
163
164 Files.delete(file);
165 } catch (final NoSuchFileException ignored) {
166
167 }
168 }
169 }
170 updateFileCounters(file, attrs);
171 return FileVisitResult.CONTINUE;
172 }
173 }