web-dev-qa-db-ja.com

Java Eclipseを介して実行しているときにファイルを見つけることができません

Eclipseのファイルから読み取る必要があるJavaアプリケーションを実行すると、Java.io.FileNotFoundException(ファイルが正しいディレクトリにある場合でも)。コマンドラインからアプリケーションをコンパイルして実行できます。この問題は、複数のプロジェクトとアプリケーションがあるEclipseでのみ発生します。ファイルを正しく見つけるために実行構成またはビルドパスを変更する必要がある設定はありますか?

21
derekerdmann

問題は、アプリケーションが相対パス名を使用している可能性が高いです。 @BalusCが言うように、相対パス名には問題があります。しかし、IMO、彼は "[y] ouはneverJava.ioで相対パスを使用するべきだと言ったとき、行き過ぎています。もの」

アプリケーションが(たとえば)FileInputStream(File)コンストラクターを使用してファイルを開くと、相対パス名は File.getAbsolutePath()

[...]それ以外の場合、このパス名はシステム依存の方法で解決されます。 UNIXシステムでは、相対パス名は、現在のユーザーディレクトリに対して解決することで絶対パス名になります。 Microsoft Windowsシステムでは、相対パス名は、もしあれば、そのパス名で指定されたドライブの現在のディレクトリに対して解決することにより絶対になります。そうでない場合は、現在のユーザーディレクトリに対して解決されます。

そのため、すぐに、「現在のディレクトリ」という概念は、WindowsプラットフォームとUNIXプラットフォームで異なるニュアンスを持つことがわかります。 2番目の問題は、pure Javaでは現在のディレクトリが何であるかを明確に見つけることはできず、pure Javaを使用して現在のJVMのディレクトリを変更することはできません。 user.dir」システムプロパティは現在のディレクトリに設定されますが、アプリケーションがプロパティを変更するのを止めるものはありません。したがって、完全に依存することはできません。 dir "は、一般的な相対パスではなく、空のパスの解決方法を変更するだけです。)

それで、これについてどうすればいいですか?

  • 1つのオプションは、絶対パス名を使用してファイルを参照することです。これは(ほとんど)すべての場合において信頼性がありますが、ユーザーがパス名を入力する必要がある場合、または固定(または構成済み)の絶対パス名を避ける必要がある場合、絶対パス名を使用すると問題が発生する可能性があります。

  • 2番目のオプションは、クラスパスの相対パス名を使用し、アプリケーションのインストールディレクトリに関連するファイルを見つけることです。これが必要な場合は機能しますが、Fileを何らかのライブラリメソッドに渡す必要がある場合は問題が発生します。また、ユーザーのアプリケーション設定を見つけようとしても役に立ちません。 (一般に、ユーザー設定をインストールディレクトリに入れるのは間違いです...)

  • 3番目のオプションは、他の場所から取得した絶対ディレクトリに関連するファイルに名前を付けることです。例えばnew File(System.getProperty("home.dir"), "foo/bar");

  • 最後のオプションは、相対パス名を使用し、ユーザーが現在のディレクトリを知っていると想定することです。ユーザーがコマンドラインから実行する多くのアプリケーションにとって、これは正しいソリューションです。

Eclipseの特定のケースでは、簡単な解決策があります。アプリケーションの起動に使用している「実行構成」に移動し、「引数」タブを開いて、「その他」ラジオボタンをクリックします。次に、起動したアプリケーションの作業ディレクトリとして絶対パス名を入力します。子JVMが起動すると、指定された作業ディレクトリが現在のディレクトリになります。

30
Stephen C

別のオプションは、「現在のパス」が環境内のどのディレクトリを指しているかを単純に把握することです。理解したら、そこからソリューションを選択できます。ファイルの場所への適切な相対パスを使用するか、ファイルを再配置することです。

    File testFile = new File("");
    String currentPath = testFile.getAbsolutePath();
    System.out.println("current path is: " + currentPath);
8
tgmoor

EclipseでデフォルトのJavaアプリケーションを作成すると、次のディレクトリ構造が得られます。

./ProjectName/ - ルートディレクトリ
./ProjectName/bin/ -.classファイルを含む出力ディレクトリ
./ProjectName/src/ -.Javaファイルを含むソースディレクトリ

アプリケーションが「./data.txt」を要求すると、ルートディレクトリを基準にして検索します。これは「作業ディレクトリ」であり、上記のMartinの回答に従って引数タブで設定できます。

あなたはそれがコマンドラインから機能すると言いますか?これはおそらく、Java binary。を実行するときにbinまたはsrcフォルダー内にいるためです。この場合の作業ディレクトリは、コマンドプロンプトが現在含まれているディレクトリです。たとえば、 、/ src /ディレクトリに移動し、javac *.Javaその後、そこからファイルを実行し、/ src /ディレクトリ内で「./data.txt」を検索します。/bin /ディレクトリ内に移動してそこからアプリケーションを実行すると、/ bin /ディレクトリに関連するファイルが検索されます。

7
Gunslinger47

私は同様の問題を抱えていました.srcフォルダー内のcobolcopybooksという名前のフォルダーにファイルを配置し、classloader.getResource( "cobolcopybooks/demostud.cob")を使用してプロジェクト内でそれらにアクセスしようとしましたが、nullポインター例外が発生していましたいくつかの試みが失敗した後、ワークスペースをクリーニングしてビルドすることで数回試しました。つまり、これらのファイルは、実行時にルートディレクトリがbinディレクトリになり、そこでそれらのファイルを検索するため、他のクラスファイルとともに表示される必要があります。

2

Java.ioで相対パスを使用するneverを使用する必要があります。パスは現在の作業ディレクトリに依存しますが、これはアプリケーションの起動方法に依存するため、すべての環境で同じではありません。これはJavaアプリケーション。移植性の問題!常に絶対パスを使用してください。たとえば、UNIXの場合はc:/path/to/file.extまたは/path/to/file.ext(先頭のスラッシュ)、コンソーツ(またはディスク文字がWindows無関係)。

アプリケーションと一緒にいくつかのファイルを出荷したいときはいつでも、それらをclasspathにも配置するのが一般的です。この方法では、 ClassLoader#getResource() を使用してその場所を取得できます。 URL を返します。 URL#toURI() または URL#getPath() を使用して、それを Java.io.File のコンストラクターに渡してから使用できます。さらに通常の方法。

Eclipseプロジェクトでは、srcフォルダー(Javaソースが行く場所)は基本的にクラスパスのルートです。さらに、他のすべてのプロジェクトと(外部)プロジェクトのBuild Pathで取得されるフォルダー。

特定のファイルをクラスパスのrootに配置したと仮定します。

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = classLoader.getResource("file.ext");
File file = new File(url.getPath());
FileInputStream input = new FileInputStream(file);
// ...

ClassLoader#getResourceAsStream() を使用して InputStream を直接取得することもできます。

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("file.ext");
// ...

パッケージ内に配置されている場合は、通常のパス名を使用できます。

URL url = classLoader.getResource("com/example/file.ext");
// ...

または

InputStream input = classLoader.getResourceAsStream("com/example/file.ext");
// ...
2
BalusC

ユーザーがファイルへの完全なファイルパスを入力せず、「myfilenameonly」などのように入力すると仮定します。この場合、File file = new File(".", args[0])はファイルを見つけるために必要です(渡された最初の引数に注意してください)。

すべてのプラットフォーム:File.getParent()は親ディレクトリを返しません。ファイルシステム固有の方法で「..」または親ディレクトリの名前を返す必要があります。

たとえば、ファイルが置かれているディレクトリへのフルパスを指定せずにファイル「myfilenameonly」を作成すると、File.getParent()はnullを返します。

さらに詳しく: http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=1228537

1
Marcos Leão