Изменение текущего рабочего каталога в Java?
Как я могу изменить текущий рабочий каталог из программы Java? Все, что я смог найти по этому вопросу, утверждает, что вы просто не можете этого сделать, но я не могу поверить, что это действительно так.
У меня есть фрагмент кода, который открывает файл, используя жестко заданный относительный путь к файлу из каталога, в котором он обычно запускается, и я просто хочу иметь возможность использовать этот код из другой программы Java без необходимости запускать его из определенного каталога. Кажется, что вы просто должны быть в состоянии позвонить System.setProperty( "user.dir", "/path/to/dir" )
, но, насколько я могу понять, вызов этой линии просто молча терпит неудачу и ничего не делает.
13 ответов:
Нет надежного способа сделать это в чистой Java. Установка свойства
user.dir
черезSystem.setProperty()
илиjava -Duser.dir=...
, по-видимому, влияет на последующие созданияFiles
, но не напримерFileOutputStreams
.Альтернативой является настройка скрипта для запуска Java из другого каталога или использование собственного кода JNI , Как предлагается ниже.
File(String parent, String child)
конструктор может помочь, если вы создадите путь к каталогу отдельно от пути к файлу, что позволит упростить обмен.Соответствующее Солнце баг был закрыт в 2008 году как "не исправится".
Если вы запустите вашу устаревшую программу с помощью ProcessBuilder , Вы сможете указать ее рабочий каталог .
Существует способ сделать это с помощью системного свойства "пользователь.dir". Ключевая часть, которую нужно понять, заключается в том, что getAbsoluteFile() должен быть вызван (как показано ниже), иначе относительные пути будут разрешены против пользователя default".реж" значение.
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"); } }
Можно изменить PWD, используя JNA/JNI для вызова libc. У ребят из JRuby есть удобная библиотека java для выполнения вызовов POSIX под названием jna-posix Вот Информация maven
Вы можете увидеть пример его использования здесь (Код Clojure, извините). Посмотрите на функцию chdirToRoot
Если я правильно понимаю, программа Java начинается с копии текущих переменных окружения. Любые изменения через
System.setProperty(String, String)
изменяют копию, а не исходные переменные среды. Не то чтобы это давало основательную причину, почему Солнце выбрало такое поведение, но, возможно, оно проливает немного света...
Как уже упоминалось, вы не можете изменить CWD JVM, но если бы вы запустили другой процесс с помощью Runtime.exec() можно использовать перегруженный метод, который позволяет указать рабочий каталог. Это не совсем для запуска вашей Java-программы в другом каталоге, но для многих случаев, когда нужно запустить другую программу, например Perl-скрипт, вы можете указать рабочий каталог этого скрипта, оставив рабочий каталог JVM без изменений.
См. Время выполнения.exec javadocs
В частности,
public Process exec(String[] cmdarray,String[] envp, File dir) throws IOException
Где
dir
- рабочий каталог для запуска подпроцесса в
Рабочий каталог-это функция операционной системы (устанавливается при запуске процесса). Почему бы вам просто не передать свое собственное системное свойство (
-Dsomeprop=/my/path
) и не использовать его в своем коде в качестве родителя вашего файла:File f = new File ( System.getProperty("someprop"), myFilename)
Здесь разумнее / проще всего изменить свой код так, чтобы вместо открытия файла предполагать, что он существует в текущем рабочем каталоге (я предполагаю, что вы делаете что-то вроде
new File("blah.txt")
, просто построить путь к файлу самостоятельно.Пусть пользователь переходит в базовый каталог, читает его из файла конфигурации, возвращается к
user.dir
, если другие свойства не могут быть найдены и т. д. Но гораздо проще улучшить логику в вашей программе, чем изменить ее окружение. переменные работают.
Я пытался вызвать
Кажется, это работает. Но
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
Вы можете использовать
Новый файл ("relative / path").getAbsoluteFile ()
После
Система.setProperty ("пользователь.реж.", "/некоторые / каталоги")
System.setProperty("user.dir", "C:/OtherProject"); File file = new File("data/data.csv").getAbsoluteFile(); System.out.println(file.getPath());
Напечатает
C:\OtherProject\data\data.csv
Другой возможный ответ на этот вопрос может зависеть от причины открытия файла. Это файл свойств или файл, имеющий некоторую конфигурацию, связанную с вашим приложением?
В этом случае вы можете попробовать загрузить файл через загрузчик classpath, таким образом, вы можете загрузить любой файл, к которому имеет доступ Java.
Если вы запускаете свои команды в оболочке, вы можете написать что-то вроде "java-cp" и добавить любые каталоги, которые вы хотите отделить ":" если java не найдет что-то в одном каталоге, он попытается найти их в других каталогах, вот что я делаю.
Use 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);