我试图找到给定路径是否可能是使用java的另一个路径的子路径。这两条路径可能都不存在。
说c:\Program Files\My Company\test\My App
可能是c:\Program Files
的孩子。
目前我正在使用
执行此操作boolean myCheck(File maybeChild, File possibleParent)
{
return maybeChild.getAbsolutePath().startsWith( possibleParent.getAbsolutePath());
}
答案 0 :(得分:50)
您还可以使用 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”。
答案 1 :(得分:12)
File parent = maybeChild.getParentFile();
while ( parent != null ) {
if ( parent.equals( possibleParent ) )
return true;
parent = parent.getParentFile();
}
return false;
答案 2 :(得分:11)
除了路径可能不存在(并且规范化可能不成功)之外,这看起来像一个合理的方法,应该在简单的情况下起作用。
您可能希望在循环中查看“可能的孩子”上的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;
}
请注意,如果您希望子关系 strict (即目录不是其自身的子目录),您可以将第9行的初始child
分配更改为{{ 1}}所以第一次检查发生在孩子的包含目录上。
答案 3 :(得分:7)
这适用于您的示例。如果孩子是相对路径,它也将返回true
(这通常是可取的。)
boolean myCheck(File maybeChild, File possibleParent)
{
URI parentURI = possibleParent.toURI();
URI childURI = maybeChild.toURI();
return !parentURI.relativize(childURI).isAbsolute();
}
答案 4 :(得分:4)
虽然我会使用getCanonicalPath()
而不是getAbsolutePath()
,但它可能会正常工作。这应该规范化任何奇怪的路径,如x/../y/z
,否则会搞砸匹配。
答案 5 :(得分:2)
maybeChild.getCanonicalPath().startsWith( possibleParent.getCanonicalPath() );
答案 6 :(得分:1)
注意相对路径!我认为最简单的解决方案是这样的:
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)
答案 7 :(得分:0)
旧问题,但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);
}
答案 8 :(得分:0)
令人惊讶的是,没有简单但实用的解决方案。
接受的答案确实认为与子目录相同,这是错误的。
以下是仅使用 java.nio.file.Path API的一种:
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();
}
答案 9 :(得分:0)
在测试路径是否相等时,应考虑以下注意事项:
java.io.File
和 String
都不能使用的原因。C:\abc
不是 C:\abcd
的祖先,甚至也不是 String.startsWith()
的直接父,因此无法使用 C:\Program Files
API。C:\PROGRA~1
与 Files.isSameFile()
是同一目录,Path.startsWith()
(来自 NIO.2)是唯一可以处理此权限的 API。这是 Files.isSameFile()
方法不支持的。C:\Documents and Settings
在某种程度上支持这种,因此C:\Users\Public
确实是Path.startsWith()
的祖先。同样,这也是自定义代码比 boolean isAncestorOf(final Path parent, final Path child) {
final Path absoluteParent = parent.toAbsolutePath().normalize();
final Path absoluteChild = child.toAbsolutePath().normalize();
if (absoluteParent.getNameCount() >= absoluteChild.getNameCount()) {
return false;
}
final Path immediateParent = absoluteChild.getParent();
if (immediateParent == null) {
return false;
}
return isSameFileAs(absoluteParent, immediateParent) || isAncestorOf(absoluteParent, immediateParent);
}
boolean isSameFileAs(final Path path, final Path path2) {
try {
return Files.isSameFile(path, path2);
}
catch (final IOException ioe) {
return path.toAbsolutePath().normalize().equals(path2.toAbsolutePath().normalize());
}
}
API(请参阅 this most-voted answer)稍微好一点的地方。综上所述,解决方案可能是这样的。爪哇:
fun Path.isAncestorOf(child: Path): Boolean {
val absoluteParent = toAbsolutePath().normalize()
val absoluteChild = child.toAbsolutePath().normalize()
if (absoluteParent.nameCount >= absoluteChild.nameCount) {
return false
}
val immediateParent = absoluteChild.parent
?: return false
return absoluteParent.isSameFileAs(immediateParent) || absoluteParent.isAncestorOf(immediateParent)
}
fun Path.isSameFileAs(that: Path): Boolean =
try {
Files.isSameFile(this, that)
}
catch (_: NoSuchFileException) {
toAbsolutePath().normalize() == that.toAbsolutePath().normalize()
}
科特林:
#!groovy
def label = "debug-${UUID.randomUUID().toString()}"
podTemplate(label: label, slaveConnectTimeout: '10', containers: [
containerTemplate(
name: 'docker-in-docker',
image: 'cfzen/dind:java11',
privileged: true,
workingDir: '/home/jenkins/agent',
ttyEnabled: true,
command: 'cat',
envVars: [
envVar(key: 'TESTCONTAINERS_HOST_OVERRIDE', value: 'tcp://localhost:2375'),
envVar(key: 'TESTCONTAINERS_RYUK_DISABLED', value: 'true'),
]
),
containerTemplate(
name: 'helm-kubectl',
image: 'dtzar/helm-kubectl',
workingDir: '/home/jenkins/agent/',
ttyEnabled: true,
command: 'cat'
)
],
volumes: [hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),],
annotations: [
podAnnotation(key: 'iam.amazonaws.com/role',
value: 'arn:aws:iam::xxxxxxxxxxx')
],
)
{
node(label) {
deleteDir()
stage('Checkout') {
checkout scm
def shortCommit = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
currentBuild.description = "${shortCommit}"
}
stage('Run Integration tests') {
container('docker-in-docker') {
withCredentials([
usernamePassword(credentialsId: 'jenkins-artifactory-credentials',
passwordVariable: 'ARTIFACTORY_SERVER_PASSWORD',
usernameVariable: 'ARTIFACTORY_SERVER_USERNAME')])
{
echo 'Run Integration tests'
sh("mvn -B clean verify -q -s mvn/local-settings.xml")
}
}
}