JavaがFile
オブジェクトの作成中に相対パスを解決する方法を理解しようとしています。
使用OS:Windows
以下のスニペットでは、パスが見つからないためIOException
を取得しています。
@Test
public void testPathConversion() {
File f = new File("test/test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
ここでの私の理解は、Javaは提供されたパスを絶対パスとして扱い、パスが存在しない場合にエラーを返すということです。理にかなっています。
上記のコードを更新して相対パスを使用する場合:
@Test
public void testPathConversion() {
File f = new File("test/../test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
新しいファイルを作成し、以下の出力を提供します。
test\..\test.txt
C:\JavaForTesters\test\..\test.txt
C:\JavaForTesters\test.txt
この場合、パスには「/../」が含まれているため、提供されたパスが存在しない場合でも、Javaはこれを相対パスとして扱い、user.dir
にファイルを作成します。これも理にかなっています。
しかし、次のように相対パスを更新すると:
@Test
public void testPathConversion() {
File f = new File("test/../../test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
次にIOExceptionが発生します:アクセスが拒否されました。
私の質問は:
"test/../test.txt"
が相対パスとして扱われ、"user.dir"
にファイルを作成しますが、"test/../../test.txt"
はエラーを返しますか?パス"test/../../test.txt"
のファイルはどこで作成しようとしますか?指定した相対パスが見つからない場合、ファイルはuser.dir
に作成されているようです。したがって、以下の2つのシナリオは同じことをしているように見えます。
//scenario 1
File f = new File("test/../test.txt");
f.createNewFile();
//scenario 2
File f = new File("test.txt");
f.createNewFile();
それでは、シナリオ2の代わりにシナリオ1を使用する現実のケースはありますか?
私はここで明白な何かを見逃している、または基本的に相対パスを誤解していると思います。 FileのJavaドキュメントを調べましたが、これについての説明が見つかりません。 Stack Overflowには相対パスに関してかなりの数の質問が投稿されていますが、調べたのは特定のシナリオに関するものであり、相対パスの解決方法に関するものではありません。
誰かが私にこれがどのように機能するかを説明したり、いくつかの関連リンクを指摘してくれたら素晴らしいでしょうか?
working directory
の概念があります。
このディレクトリは、.
(ドット)で表されます。
相対パスでは、他のすべてはそれに関連しています。
.
(作業ディレクトリ)を置くだけで、プログラムを実行できます。
作業ディレクトリを変更できる場合がありますが、一般的には
ドットが表すもの。あなたの場合、これはC:\JavaForTesters\
だと思います。
test\..\test.txt
は次を意味します:サブディレクトリtest
作業ディレクトリで、1つ上のレベルに移動してから、
ファイルtest.txt
。これは基本的にtest.txt
と同じです。
詳細については、こちらをご覧ください。
http://docs.Oracle.com/javase/7/docs/api/Java/io/File.html
http://docs.Oracle.com/javase/tutorial/essential/io/pathOps.html
パスがルートディレクトリ、つまりWindowsのC:\
またはUnixまたはJavaリソースパスの/
で始まる場合、それは絶対パスと見なされます。それ以外はすべて相対的なので、
new File("test.txt") is the same as new File("./test.txt")
new File("test/../test.txt") is the same as new File("./test/../test.txt")
getAbsolutePath
とgetCanonicalPath
の主な違いは、最初のパスが親と子のパスを連結するため、ドットが含まれる場合があることです:..
または.
。 getCanonicalPath
は、特定のファイルに対して常に同じパスを返します。
注:File.equals
は、パスの抽象的な形式(getAbsolutePath
)を使用してファイルを比較するため、同じ2つのFile
オブジェクトが等しくなく、File
sが等しい場合があります。 Map
やSet
などのコレクションで使用するのは安全ではありません。
作業ディレクトリは、実質的にすべてのオペレーティングシステムとプログラム言語などで共通の概念です。プログラムが実行されているディレクトリです。これは通常、アプリケーションが存在するディレクトリです(常にではありませんが、変更する方法があります)。
相対パスは、ドライブ指定子なしで開始するパスです。したがって、Linuxでは/
で始まりません。WindowsではC:\
で始まりません。これらは常に作業ディレクトリから始まります。
絶対パスは、ドライブ(またはネットワークパスのマシン)指定子で始まるパスです。彼らは常にそのドライブの開始から行きます。
Javaがプログラムを実行する方法を知っていれば、相対パスを最もよく理解できます。
Javaでプログラムを実行するときの作業ディレクトリの概念があります。たとえば、/User/home/Desktop/projectRoot/src/topLevelPackage/
の下でIOを実行するFileHelper
というクラスがあると仮定します。
Java
を呼び出してプログラムを実行する場合に応じて、作業ディレクトリが異なります。 IDE内からプログラムを実行する場合、ほとんどの場合projectRoot
になります。
この場合、$ projectRoot/src : Java topLevelPackage.FileHelper
はsrc
になります。
この場合、$ projectRoot : Java -cp src topLevelPackage.FileHelper
はprojectRoot
になります。
この場合、$ /User/home/Desktop : Java -cp ./projectRoot/src topLevelPackage.FileHelper
はDesktop
になります。
(Assuming $ is your command Prompt with standard Unix-like FileSystem. Similar correspondence/parallels with Windows system)
したがって、相対パスルート(.)
は作業ディレクトリに解決されます。したがって、ファイルを書き込む場所をより確実にするために、以下のアプローチを検討すると言われています。
package topLevelPackage
import Java.io.File;
import Java.nio.file.Path;
import Java.nio.file.Paths;
public class FileHelper {
// Not full implementation, just barebone stub for path
public void createLocalFile() {
// Explicitly get hold of working directory
String workingDir = System.getProperty("user.dir");
Path filePath = Paths.get(workingDir+File.separator+"sampleFile.txt");
// In case we need specific path, traverse that path, rather using . or ..
Path pathToProjectRoot = Paths.get(System.getProperty("user.home"), "Desktop", "projectRoot");
System.out.println(filePath);
System.out.println(pathToProjectRoot);
}
}
お役に立てれば。
WindowsおよびNetbeansでは、相対パスを次のように設定できます。
new FileReader("src\\PACKAGE_NAME\\FILENAME");
LinuxおよびNetbeansでは、相対パスを次のように設定できます。
new FileReader("src/PACKAGE_NAME/FILENAME");
Source Packages
内にコードがある場合、Eclipseまたは他のIDEで同じかどうかわかりません
質問に少しだけ関連がありますが、この問題に頭を包むようにしてください。直感的ではない:
import Java.nio.file.*;
class Main {
public static void main(String[] args) {
Path p1 = Paths.get("/personal/./photos/./readme.txt");
Path p2 = Paths.get("/personal/index.html");
Path p3 = p1.relativize(p2);
System.out.println(p3); //prints ../../../../index.html !!
}
}