Javaの現在の作業ディレクトリを変更しますか?


169

Javaプログラム内から現在の作業ディレクトリを変更するにはどうすればよいですか?この問題について私が見つけたすべてのものは、あなたが単にそれを行うことができないと主張していますが、それが本当にそうであるとは信じられません。

通常起動されるディレクトリからのハードコードされた相対ファイルパスを使用してファイルを開くコードがあり、別のJavaプログラム内からそのコードを使用できるようにしたいのです。特定のディレクトリ。あなたはを呼び出すことができるように思えますがSystem.setProperty( "user.dir", "/path/to/dir" )、私が理解できる限り、その行を呼び出すと、黙って失敗し、何もしません。

現在の作業ディレクトリを取得でき、さらに相対ファイルパスを使用してファイルを開くことができるという事実がなければ、Javaがこれを許可していなかったとしたら、私は理解できます。


1
情報の取得と使用は、情報の変更とは異なります。たとえば、Windowsでは環境変数を簡単に取得できますが、(システム全体で)環境変数を変更することは困難です。
PhiLho 2009年

1
bugs.java.com/bugdatabase/view_bug.do?bug_id=4045688は、評価セクションに「それ以来、これ以上顧客が登場したり、その他の方法で特定されたりすることはありません...」と述べており、2018年現在、約175.000この質問の表示:-(
Wolfgang Fahl

回答:


146

純粋なJavaでこれを行う信頼できる方法はありません。またはuser.dirを介してプロパティを設定すると、以降のの作成に影響するようですが、例には影響しません。System.setProperty()java -Duser.dir=...FilesFileOutputStreams

File(String parent, String child)コンストラクタは、簡単に交換できるよう、あなたのファイルパスとは別に自分のディレクトリパスを構築する場合に役立ちます。

別の方法として、別のディレクトリからJavaを実行するようにスクリプトを設定するか、以下に示すように JNIネイティブコード使用します

関連するSunのバグは「修正されない」ため、2008年にクローズされました。


12
Javaとc#の間に「Javaの人たちは何をしているのかよくわかっている」と思うような違いは1つもないと思います
Jake

2
Javaに少なくとも「このディレクトリから開始する...」というパラメータがないとは信じられません...
rogerdpack 2013年

5
Javaの防御において(そして私はこの機能を望んでいるUNIXの男です)...それはOSの詳細にとらわれないことを意図されたVMです。「現在の作業ディレクトリ」のイディオムは、一部のオペレーティングシステムでは使用できません。
Tony K.

4
Javaに公平を期するために、彼らは最初にそれを行わなければなりませんでした。C#には、多くの分野での過ちから学ぶことができるという利点がありました。
ライアンザリーチ2014年

3
@VolkerSeibt:さらなる調査の結果、user.dirは、最初にテストしたクラスを含め、一部のクラスでしか機能しないようです。new FileOutputStream("foo.txt").close();プログラムがuser.dirを変更した場合でも、元の作業ディレクトリにファイルを作成します。
マイケルマイヤーズ

37

従来のプログラムをProcessBuilderで実行する場合は、その作業ディレクトリを指定できます。


1
のルートは私がとったルートです。次のようにして、別の作業ディレクトリから実行可能ファイルを実行することができました。ProcessBuilder pBuilder = new ProcessBuilder( "C:\\ path \\ to \\ working \\ dir \\ executable.exe"); pBuilder.directory(WorkingDir); プロセスp = pBuilder.start();
CatsAndCode 2018

29

そこシステムプロパティ「はuser.dir」を使用してこれを行う方法は。理解すべき重要な部分は、getAbsoluteFile()を呼び出す必要がある(以下に示すように)必要があることです。そうしないと、相対パスがデフォルトの「user.dir」値に対して解決されます。

import java.io.*;

public class FileUtils
{
    public static boolean setCurrentDirectory(String directory_name)
    {
        boolean result = false;  // Boolean indicating whether directory was set
        File    directory;       // Desired current working directory

        directory = new File(directory_name).getAbsoluteFile();
        if (directory.exists() || directory.mkdirs())
        {
            result = (System.setProperty("user.dir", directory.getAbsolutePath()) != null);
        }

        return result;
    }

    public static PrintWriter openOutputFile(String file_name)
    {
        PrintWriter output = null;  // File to open for writing

        try
        {
            output = new PrintWriter(new File(file_name).getAbsoluteFile());
        }
        catch (Exception exception) {}

        return output;
    }

    public static void main(String[] args) throws Exception
    {
        FileUtils.openOutputFile("DefaultDirectoryFile.txt");
        FileUtils.setCurrentDirectory("NewCurrentDirectory");
        FileUtils.openOutputFile("CurrentDirectoryFile.txt");
    }
}

3
絶対パスが重要
HackNone 2013年

5
ただし、現在の作業ディレクトリは変更されません。の値のみuser.dir。絶対パスがクリティカルになるという事実はそれを証明します。
ローンの侯爵

18

JNA / JNIを使​​用してlibcを呼び出すことで、PWDを変更することができます。JRubyの人たちは、jna-posixと呼ばれるPOSIX呼び出しを行うための便利なJavaライブラリを持っていますここだMavenの情報

ここでその使用例を見ることができます(Clojureコード、申し訳ありません)。関数chdirToRootを見てください。


1
jna-posixの最新バージョンはないようです。私はフォークして追加しました:github.com/pbiggar/jnr-posix。これでPWDを変更できることが確認できました。
ポールビガー

はい。そのファイルをリファクタリングして、ファイルにリンクされているこの回答を忘れてしまいました。修繕。
Allen Rohner、2013

あなたはこれを行うことができますが、あなたも変更しない場合はuser.dir、システムのプロパティを、その後File.getAbsolutePath()に対して解決しますuser.dirOSに対するファイル解決さにパス名がディレクトリを作業中に、。
モリー、2014年

元の質問に関連して、jnr-posixを使用して、Javaの現在の作業ディレクトリを変更するにはどうすればよいですか。chdirメソッドを使用するには、どのクラスのインスタンスを作成する必要がありますか?与えられたClojureの例は本当に理解できませんでした。前もって感謝します。
Sam Saint-Pettersen 2014年

12

前述のように、JVMのCWDを変更することはできませんが、Runtime.exec()を使用して別のプロセスを起動する場合は、作業ディレクトリを指定できるオーバーロードメソッドを使用できます。これは実際にはJavaプログラムを別のディレクトリで実行するためのものではありませんが、Perlスクリプトなどの別のプログラムを起動する必要がある場合の多くの場合、JVMの作業ディレクトリを変更せずに、そのスクリプトの作業ディレクトリを指定できます。

Runtime.exec javadocsを参照してください

具体的には

public Process exec(String[] cmdarray,String[] envp, File dir) throws IOException

dirサブプロセスを実行する作業ディレクトリはどこですか


1
これは、受け入れられた回答(「純粋なJavaでこれを行う信頼できる方法はありません。」で始まる)よりも良い回答のようです。この回答を承認済みの回答と見なすように請願する方法はありますか?
ジョン

11

私が正しく理解していれば、Javaプログラムは現在の環境変数のコピーから始まります。による変更System.setProperty(String, String)は、元の環境変数ではなく、コピーを変更しています。これが、Sunがこの動作を選択した理由についての完全な理由を提供するわけではありませんが、おそらくそれは少し光を放ちます...


2
環境変数とプロパティを混同しているようです。前者はOSから継承され、後者はを使用してコマンドラインで定義できます-D。しかし、私は同意します。JVM user.dirでは、OSからコピーするなどの事前定義されたプロパティを開始し、後で変更することは役に立ちません。
maaartinus

変更はとにuser.dir影響File.getAbsolutePath()しますFile.getCanonicalPath()が、OSの作業ディレクトリの概念には影響しません。これは、ファイルにアクセスするときにファイルパス名を解決する方法を決定します。
モリー

5

作業ディレクトリはオペレーティングシステムの機能です(プロセスの開始時に設定されます)。自分のSystemプロパティを渡してみませんか(-Dsomeprop=/my/path)を、コードでFileの親として使用しないでください。

File f = new File ( System.getProperty("someprop"), myFilename)

コードにはハードコードされたファイルパスが含まれており、おそらく作業元の親ディレクトリを指定しないハードコードされたコンストラクタを使用しているためです。少なくとも、私が持っている状況です:)
David Mann

4

ここで行うよりスマートで簡単なことは、現在の作業ディレクトリにあると想定してファイルを開くのではなく、コードを変更することです(私はあなたが new File("blah.txt")して、ファイルへのパスを自分で構築するだけです)。

ユーザーにベースディレクトリを渡させ、構成ファイルから読み取らせuser.dir、他のプロパティが見つからない場合はフォールバックするなどを許可します。ただし、プログラムのロジックを改善する方が、方法を変更するよりもずっと簡単です。環境変数が機能します。


2

呼び出してみました

String oldDir = System.setProperty("user.dir", currdir.getAbsolutePath());

動作しているようです。だが

File myFile = new File("localpath.ext"); InputStream openit = new FileInputStream(myFile);

でも投げFileNotFoundExceptionます

myFile.getAbsolutePath()

正しいパスを示しています。私はこれ読みました。私は問題だと思います:

  • Javaは現在のディレクトリを新しい設定で認識します。
  • ただし、ファイル処理はオペレーティングシステムによって行われます。残念ながら、それは新しいセットの現在のディレクトリを知りません。

解決策は次のとおりです。

File myFile = new File(System.getPropety("user.dir"), "localpath.ext");

これは、JVMによって認識されている現在のディレクトリを使用して、ファイルオブジェクトを絶対ファイルとして作成します。しかし、そのコードは中古クラスに存在している必要があり、再利用されたコードの変更が必要です。

~~~~ JcHartmut


「ファイルオブジェクトを作成します」-はい。しかし、それはファイルシステムにファイルを作成しません。その後、file.createNewFile()を使用するのを忘れていました。
Gangnus

2

使用できます

新しいFile( "relative / path")。getAbsoluteFile()

System.setProperty( "user.dir"、 "/ some / directory")

System.setProperty("user.dir", "C:/OtherProject");
File file = new File("data/data.csv").getAbsoluteFile();
System.out.println(file.getPath());

印刷します

C:\OtherProject\data\data.csv

1
この動作はJava 11で変更されたことに注意してください。bugs.openjdk.java.net/browse/JDK-8202127を参照してください。彼らは使用をお勧めしませんSystem.setProperty("user.dir", "/some/directory")
Martin

0

この質問に対する他の可能な答えは、ファイルを開いている理由によって異なります。これは、プロパティファイルですか、アプリケーションに関連するいくつかの構成を持つファイルですか?

これが当てはまる場合は、クラスパスローダーを介してファイルをロードすることを検討してください。これにより、Javaがアクセスできる任意のファイルをロードできます。


0

シェルでコマンドを実行する場合は、「java -cp」のように記述し、「:」で区切って任意のディレクトリを追加できます。javaが1つのディレクトリで何かを見つけられない場合、他のディレクトリでそれらを見つけようとします。私がやっていることです。


0

JNIまたはJNAを使用して、プロセスの実際の作業ディレクトリを変更できます。

JNIでは、ネイティブ関数を使用してディレクトリを設定できます。POSIXメソッドはchdir()です。Windowsでは、を使用できますSetCurrentDirectory()

JNAを使用すると、ネイティブ関数をJavaバインダーにラップできます。

Windowsの場合:

private static interface MyKernel32 extends Library {
    public MyKernel32 INSTANCE = (MyKernel32) Native.loadLibrary("Kernel32", MyKernel32.class);

    /** BOOL SetCurrentDirectory( LPCTSTR lpPathName ); */
    int SetCurrentDirectoryW(char[] pathName);
}

POSIXシステムの場合:

private interface MyCLibrary extends Library {
    MyCLibrary INSTANCE = (MyCLibrary) Native.loadLibrary("c", MyCLibrary.class);

    /** int chdir(const char *path); */
    int chdir( String path );
}

-1

FileSystemViewを使用する

private FileSystemView fileSystemView;
fileSystemView = FileSystemView.getFileSystemView();
currentDirectory = new File(".");
//listing currentDirectory
File[] filesAndDirs = fileSystemView.getFiles(currentDirectory, false);
fileList = new ArrayList<File>();
dirList = new ArrayList<File>();
for (File file : filesAndDirs) {
if (file.isDirectory())
    dirList.add(file);
else
    fileList.add(file);
}
Collections.sort(dirList);
if (!fileSystemView.isFileSystemRoot(currentDirectory))
    dirList.add(0, new File(".."));
Collections.sort(fileList);
//change
currentDirectory = fileSystemView.getParentDirectory(currentDirectory);

import javax.swing.filechooser.FileSystemView;
Borneq 2013

1
この回答は質問とは関係ありません。
アーロンディグラ2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.