Изменение текущего рабочего каталога в Java? - PullRequest
158 голосов
/ 08 мая 2009

Как я могу изменить текущий рабочий каталог из программы Java? Все, что я смог найти в этой проблеме, утверждает, что вы просто не можете этого сделать, но я не могу поверить, что это действительно так.

У меня есть фрагмент кода, который открывает файл с использованием жестко заданного относительного пути к файлу из каталога, в котором он обычно запускается, и я просто хочу иметь возможность использовать этот код из другой Java-программы без необходимости запуска это из определенного каталога. Похоже, что вы просто должны быть в состоянии вызвать System.setProperty( "user.dir", "/path/to/dir" ), но, насколько я могу понять, вызов этой линии просто молча завершается ошибкой и ничего не делает.

Я бы понял, если бы Java не позволяла вам сделать это, если бы не тот факт, что он позволяет получить текущий рабочий каталог и даже позволяет открывать файлы, используя относительные пути к файлам ....

Ответы [ 13 ]

140 голосов
/ 08 мая 2009

Нет надежного способа сделать это на чистой Java. Установка свойства user.dir с помощью System.setProperty() или java -Duser.dir=..., похоже, влияет на последующее создание Files, но не, например, FileOutputStreams.

Конструктор File(String parent, String child) может помочь, если вы строите путь к каталогу отдельно от пути к файлу, что упрощает замену.

Альтернативой является настройка скрипта для запуска Java из другого каталога или использование собственного кода JNI , как предлагается ниже .

Соответствующая ошибка Sun была закрыта в 2008 году как "не исправит".

36 голосов
/ 08 мая 2009

Если вы запустите свою унаследованную программу с ProcessBuilder , вы сможете указать ее рабочий каталог .

29 голосов
/ 21 декабря 2012

Там - это способ сделать это, используя системное свойство "user.dir". Ключевым моментом, который необходимо понять, является то, что getAbsoluteFile () должен быть вызван (как показано ниже), иначе относительные пути будут разрешены в соответствии со значением default"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");
    }
}
17 голосов
/ 21 ноября 2011

Можно изменить PWD, используя JNA / JNI для вызова libc. Ребята JRuby имеют удобную библиотеку Java для выполнения вызовов POSIX, которая называется jna-posix Вот информация maven

Пример его использования можно посмотреть здесь (код Clojure, извините). Посмотрите на функцию chdirToRoot

11 голосов
/ 06 февраля 2013

Как уже упоминалось, вы не можете изменить CWD JVM, но если вы должны были запустить другой процесс с помощью Runtime.exec (), вы можете использовать перегруженный метод, который позволяет вам указать рабочий каталог. Это на самом деле не для запуска вашей Java-программы в другом каталоге, но во многих случаях, когда нужно запустить другую программу, например, скрипт Perl, вы можете указать рабочий каталог этого скрипта, оставив рабочий каталог JVM без изменений.

См. Runtime.exec javadocs

В частности,

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

где dir - рабочий каталог для запуска подпроцесса в

11 голосов
/ 08 мая 2009

Если я правильно понимаю, программа на Java запускается с копией текущих переменных среды. Любые изменения через System.setProperty(String, String) изменяют копию, а не исходные переменные среды. Не то чтобы это дало основательную причину тому, почему Sun выбрала такое поведение, но, возможно, оно проливает немного света ...

5 голосов
/ 08 мая 2009

Рабочий каталог - это функция операционной системы (устанавливается при запуске процесса). Почему бы вам просто не передать собственное свойство System (-Dsomeprop=/my/path) и использовать его в своем коде в качестве родительского для вашего файла:

File f = new File ( System.getProperty("someprop"), myFilename)
4 голосов
/ 08 мая 2009

Разумнее / проще сделать здесь - просто изменить свой код так, чтобы вместо открытия файла предполагалось, что он существует в текущем рабочем каталоге (я предполагаю, что вы делаете что-то вроде new File("blah.txt"), просто создайте путь к файл самостоятельно.

Позвольте пользователю перейти в базовый каталог, прочитать его из файла конфигурации, вернуться к user.dir, если другие свойства не могут быть найдены, и т. Д. Но намного проще улучшить логику в вашей программе чем изменить работу переменных окружения.

2 голосов
/ 29 мая 2014

Я пытался вызвать

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");

Создает файл Object как абсолютный с текущим каталогом, который известен JVM. Но этот код должен существовать в используемом классе, он требует замены повторно используемых кодов.

~~~~ JcHartmut

1 голос
/ 10 июня 2017

Вы можете использовать

новый файл («относительный / путь»). 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
...