2011-01-20 14 views
32

javaを使用して、指定されたパスが別のパスの子であるかどうかを調べようとしています。どちらのパスも存在しない可能性があります。与えられたパスが別のパスの子である可能性があるかどうかをチェックする方法?

と言ってくださいc:\Program Files\My Company\test\My Appc:\Program Filesの可能な子です。私はgetAbsolutePath()ではなくgetCanonicalPath()を使うだろうが

は現在、私は、それがあるとして、おそらく正常に動作することを

boolean myCheck(File maybeChild, File possibleParent) 
{ 
    return maybeChild.getAbsolutePath().startsWith(possibleParent.getAbsolutePath()); 
} 
+0

この例では、すべてのファイルシステムのIOを必要としていますか? – user2586917

+0

[Java:パスがファイルの親であるかどうかをチェックする]の可能な複製(http://stackoverflow.com/questions/28698125/java-check-if-path-is-parent-of-a-file) – Suma

+0

@Sumaあなたがリンクしている質問はこの_duplicate_です。 – Jayan

答えて

41

また、はるかに簡単にこれを行うには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 

あなたはより多くの信頼性を必要とする場合は、代わりに "toAbsolutePath" の "toRealPath" を使用することができます。

+1

すばらしい解決策。 Java 7以降でのみ可能です。 –

+1

これはどのように '..'でパスを処理しますか? – Max

+0

"toAbsolutePath"メソッドはパス内で ".."を解決して動作するようにします。しかし、それをテストしてください。 –

4

でこれをやっています。これは、x/../y/zのような奇妙なパスを正規化しなければなりません。

+1

迅速で訂正されたソリューションに感謝します! – Jayan

+9

いいえ、いいえ、これは**正しくありません**!質問者の 'myCheck()'メソッドは、正規化されていても、 'C:\ Prog'が' C:\ Program Files'の子であると誤って言うでしょう。以下の@biziclopの回答を参照してください。 –

7

これはあなたの例では機能します。子供が相対パス ある場合もtrueを返します(が望ましいことが多い。)パスが存在しない可能性(とcanonicalisationが成功しない場合があります)という事実から

boolean myCheck(File maybeChild, File possibleParent) 
{ 
    URI parentURI = possibleParent.toURI(); 
    URI childURI = maybeChild.toURI(); 
    return !parentURI.relativize(childURI).isAbsolute(); 
} 
+1

[Spec](http://docs.oracle.com/javase/1.4.2/docs/api/java/net/URI.html#relativize(java.net.URI))では、「指定されたURI子ではありません]指定されたURIが返されます。 "_あなたのチェックを' parentURI.relativize(childURI)!= childURI'に変更するほうが良いでしょう。それ以外の場合は、 'maybeChild'が絶対パスであれば関数は偽陽性を返します。 – SnakE

+0

あなたは正しいです。おそらく、 'maybeChild'が' relativeParent'の子ではなく 'relativePild'の子ではなかったとすれば、あなたのメソッドは' true'を返すでしょう。これは実際には問題ではありません。なぜなら、 'File.toURI()'は絶対URIを返すことが保証されているため、 'childURI'は常に絶対的です。それでも、私が提案した小切手はうまくいくはずです。 – SnakE

+0

'maybeChild'が相対的な場合は、潜在的に何かの子になる可能性があります。 – finnw

10

Asides、これは合理的なように見えますアプローチは、直接的なケースでうまくいくはずです。

ループ内の「多分子」の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()になるようにします。そのため、最初のチェックは子のディレクトリを含んでいます。

+2

+1 OPはそれを述べていませんでしたが、実際には、実際の、既存のファイルではなくパスである可能性が高いです。 – biziclop

10
File parent = maybeChild.getParentFile(); 
while (parent != null) { 
    if (parent.equals(possibleParent)) 
    return true; 
    parent = parent.getParentFile(); 
} 
return false; 
2

maybeChild.getCanonicalPath()。startsWith(possibleParent.getCanonicalPath());

1

相対パスに注意してください。

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) 
0

古い質問が、あらかじめ1:あなたが同様のアプローチを持つことができScalaで

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) 
    } 
} 

:私は、最も簡単な解決策は、このようなものだと思います。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); 
} 
関連する問題