Изменение текущего рабочего каталога в Java?

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

Ответ 3

Там есть способ сделать это, используя системное свойство 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");
    }
}

Ответ 4

Можно изменить PWD, используя JNA/JNI для совершения вызовов в libc. У парней JRuby есть удобная java-библиотека для создания вызовов POSIX, называемых jna-posix Здесь информация о maven

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

Ответ 5

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

Ответ 6

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

Смотрите Runtime.exec javadocs

В частности,

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

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

новый файл ( "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

Ответ 11

Другой возможный ответ на этот вопрос может зависеть от причины, по которой вы открываете файл. Является ли это файлом свойств или файлом, который имеет некоторую конфигурацию, связанную с вашим приложением?

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

Ответ 12

Если вы запустите свои команды в оболочке, вы можете написать что-то вроде "java -cp" и добавить любые каталоги, которые хотите разделить ":", если java не найдет что-то в одном каталоге, он попытается найти их в другом каталогов, вот что я делаю.

Ответ 14

Использовать 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);