У меня есть (довольно глупая) проблема, я думаю.
У меня есть два класса File, и я хочу вернуть true
если он находится внутри другого. Ложь, если нет. Я не могу просто сравнить родительские файлы, потому что /a/b/c/d
также является подпапкой /a/b
.
Мой первый подход был примерно таким:
boolean areSubsets(File f1, File f2) {
if (f1.getAbsolutePath().contains(f2.getAbsolutePath()) ||
f2.getAbsolutePath().contains(f1.getAbsolutePath()) {
return true;
} else {
return false;
}
}
Но проблема в том, что существуют ложные срабатывания.
Т.е. если у нас есть f1
с path = /storage/abc
и f2
с /storage/abcabc
что вернет true
которая не true
.
Вы можете разделить на /
:
boolean areSubsets(File f1, File f2) throws IOException {
String[] p = f1.getCanonicalPath().split("/");
String[] q = f2.getCanonicalPath().split("/");
for (int i = 0; i < p.length && i < q.length; i++)
if (!p[i].equals(q[i]))
return false;
return true;
}
Основываясь на комментарии fge, в Java 7 вы можете сделать следующее:
boolean areSubsets(File f1, File f2) {
Path path1 = f1.toPath();
Path path2 = f2.toPath();
return path1.startsWith(path2) || path2.startsWith(path1);
}
#getAbsolutePath
подвержен ошибкам для этой задачи. #getCanonicalPath
этого используйте #getCanonicalPath
. Например, я мог бы создать f1
как new File("../blub/../blub/../blub/abc/sub");
и f2
как new File("abc");
и #getAbsolutePath
"потерпит неудачу" здесь.
#getCanonicalPath
может #getCanonicalPath
IOException
.
Решение, если вы используете Java 7+:
final Path testedPath = Paths.get(...).toAbsolutePath();
final Path candidateParent = Paths.get(...).toAbsolutePath();
return testedPath.startsWith(candidateParent)
&& !testedPath.equals(candidateParent);
Обратите внимание, что есть.toRealPath(), однако он может генерировать исключение IOException.
Один простой подход - использовать startsWith()
на путях, но добавить косую черту в "контейнер":
File f1, f2;
boolean contains = f2.getCanonicalPath().startsWith(
f1.getCanonicalPath() + "/");
#getAbsolutePath
подвержен ошибкам для этой задачи. #getCanonicalPath
этого используйте #getCanonicalPath
. Например, я мог бы создать f1
как new File("../blub/../blub/../blub/abc/sub");
и f2
как new File("abc");
и #getAbsolutePath
"потерпит неудачу" здесь.
Path
; у него есть инструменты для этогоPath
вместо этого, и если вам нужно, то используйте #getCanonicalPath