Как проверить, является ли данный путь возможным ребенком другого пути?
Я пытаюсь найти, если заданный путь возможен дочерним по отношению к другому пути с помощью java. Оба пути могут не существовать.
Скажите c:\Program Files\My Company\test\My App
- возможный дочерний элемент c:\Program Files
.
В настоящее время я делаю это с помощью
boolean myCheck(File maybeChild, File possibleParent)
{
return maybeChild.getAbsolutePath().startsWith( possibleParent.getAbsolutePath());
}
Ответы
Ответ 1
Вы также можете использовать java.nio.file.Path, чтобы сделать это намного легче. Метод java.nio.file.Path.startsWith, похоже, обрабатывает все возможные случаи.
Пример:
private static void isChild(Path child, String parentText) {
Path parent = Paths.get(parentText).toAbsolutePath();
System.out.println(parentText + " = " + child.startsWith(parent));
}
public static void main(String[] args) {
Path child = Paths.get("/FolderA/FolderB/File").toAbsolutePath();
isChild(child, "/FolderA/FolderB/File");
isChild(child, "/FolderA/FolderB/F");
isChild(child, "/FolderA/FolderB");
isChild(child, "/FolderA/Folder");
isChild(child, "/FolderA");
isChild(child, "/Folder");
isChild(child, "/");
isChild(child, "");
}
выходы
/FolderA/FolderB/File = true
/FolderA/FolderB/F = false
/FolderA/FolderB = true
/FolderA/Folder = false
/FolderA = true
/Folder = false
/ = true
= false
Если вам нужна более высокая надежность, вы можете использовать "toRealPath" вместо "toAbsolutePath".
Ответ 2
File parent = maybeChild.getParentFile();
while ( parent != null ) {
if ( parent.equals( possibleParent ) )
return true;
parent = parent.getParentFile();
}
return false;
Ответ 3
Помимо того, что пути могут не существовать (и канонизация может не удаться), это выглядит разумным подходом, который должен работать в прямом случае.
Возможно, вам захочется взглянуть на вызов getParentFile() в "возможно, дочернем" в цикле, проверяя, соответствует ли он родительскому элементу шаг. Вы также можете закоротить сравнение, если родительский объект не является (реальным) каталогом.
Возможно, что-то вроде следующего:
boolean myCheck(File maybeChild, File possibleParent) throws IOException
{
final File parent = possibleParent.getCanonicalFile();
if (!parent.exists() || !parent.isDirectory()) {
// this cannot possibly be the parent
return false;
}
File child = maybeChild.getCanonicalFile();
while (child != null) {
if (child.equals(parent)) {
return true;
}
child = child.getParentFile();
}
// No match found, and we've hit the root directory
return false;
}
Обратите внимание, что если вы хотите, чтобы дочерние отношения были строгими (то есть каталог не является самим собой), вы можете изменить начальное назначение child
в строке 9 на child.getParentFile()
, чтобы первая проверка произошла на дочернем содержащий каталог.
Ответ 4
Это будет работать для вашего примера. Он также вернет true
, если дочерний элемент является относительным путем
(что часто желательно).
boolean myCheck(File maybeChild, File possibleParent)
{
URI parentURI = possibleParent.toURI();
URI childURI = maybeChild.toURI();
return !parentURI.relativize(childURI).isAbsolute();
}
Ответ 5
Это, вероятно, будет работать нормально, хотя я бы использовал getCanonicalPath()
, а не getAbsolutePath()
. Это должно нормализовать любые странные пути, такие как x/../y/z
, которые в противном случае испортили бы соответствие.
Ответ 6
maybeChild.getCanonicalPath().startsWith( possibleParent.getCanonicalPath() );
Ответ 7
Имейте в виду относительные пути! Я думаю, что простейшее решение выглядит примерно так:
public boolean myCheck(File maybeChild, File possibleParent) {
if (requestedFile.isAbsolute) {
return possibleParent.resolve(maybeChild).normalize().toAbsolutePath.startsWith(possibleParent.normalize().toAbsolutePath)
} else {
return maybeChild.normalize().toAbsolutePath.startsWith(possibleParent.normalize().toAbsolutePath)
}
}
В scala вы можете иметь аналогичный подход:
val baseDir = Paths.get("/home/luvar/tmp")
val baseDirF = baseDir.toFile
//val requestedFile = Paths.get("file1")
val requestedFile = Paths.get("../.viminfo")
val fileToBeRead = if (requestedFile.isAbsolute) {
requestedFile
} else {
baseDir.resolve(requestedFile)
}
fileToBeRead.toAbsolutePath
baseDir.toAbsolutePath
fileToBeRead.normalize()
baseDir.normalize()
val isSubpath = fileToBeRead.normalize().toAbsolutePath.startsWith(baseDir.normalize().toAbsolutePath)
Ответ 8
Старый вопрос, но решение до 1.7:
public boolean startsWith(String possibleRoot, String possibleChildOrSame) {
String[] possiblePath = new File(possibleRoot).getAbsolutePath().replace('\\', '/').split("/");
String[] possibleChildOrSamePath = new File(possibleChildOrSame).getAbsolutePath().replace('\\', '/').split("/");
if (possibleChildOrSamePath.length < possiblePath.length) {
return false;
}
// not ignoring case
for (int i = 0; i < possiblePath.length; i++) {
if (!possiblePath[i].equals(possibleChildOrSamePath[i])) {
return false;
}
}
return true;
}
Для полноты решения java 1.7+:
public boolean startsWith(String possibleRoot, String possibleChildOrSame) {
Path p1 = Paths.get(possibleChildOrSame).toAbsolutePath();
Path p2 = Paths.get(possibleRoot).toAbsolutePath();
return p1.startsWith(p2);
}
Ответ 9
Удивительно, но не существует простого, но функционального решения.
Принятый ответ считает те же каталоги дочерними, что неверно.
Вот пример использования только API java.nio.file.Path:
static boolean isChildPath(Path parent, Path child){
Path pn = parent.normalize();
Path cn = child.normalize();
return cn.getNameCount() > pn.getNameCount() && cn.startsWith(pn);
}
Тестовые случаи:
@Test
public void testChildPath() {
assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F"))).isFalse();
assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F/A"))).isTrue();
assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F/A.txt"))).isTrue();
assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F/../A"))).isFalse();
assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/FA"))).isFalse();
assertThat(isChildPath(Paths.get("FolderA"), Paths.get("FolderA"))).isFalse();
assertThat(isChildPath(Paths.get("FolderA"), Paths.get("FolderA/B"))).isTrue();
assertThat(isChildPath(Paths.get("FolderA"), Paths.get("FolderA/B"))).isTrue();
assertThat(isChildPath(Paths.get("FolderA"), Paths.get("FolderAB"))).isFalse();
assertThat(isChildPath(Paths.get("/FolderA/FolderB/F"), Paths.get("/FolderA/FolderB/F/Z/X/../A"))).isTrue();
}