Изменение текущего рабочего каталога в 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 не найдет что-то в одном каталоге, он попытается найти их в другом каталогов, вот что я делаю.
Ответ 13
Это больше не работает с JDK 11:
System.setProperty("user.dir", directory.getAbsolutePath())
https://bugs.openjdk.java.net/browse/JDK-8194154
Ответ 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);