Jak mogę zmienić bieżący katalog roboczy z poziomu programu Java? Wszystko, co udało mi się znaleźć na temat problemu, mówi, że po prostu nie możesz tego zrobić, ale nie mogę uwierzyć, że tak jest naprawdę.
Mam fragment kodu, który otwiera plik za pomocą zakodowanej na stałe względnej ścieżki pliku z katalogu, w którym normalnie jest uruchomiony, i chcę tylko móc używać tego kodu z innego programu Java bez konieczności uruchamiania go od wewnątrz określony katalog. Wygląda na to, że powinieneś móc po prostu zadzwonić System.setProperty( "user.dir", "/path/to/dir" )
, ale o ile mogę się zorientować, dzwonienie na tę linię po prostu cicho zawodzi i nic nie robi.
Zrozumiałbym, gdyby Java nie pozwoliła ci tego zrobić, gdyby nie fakt, że pozwala ci uzyskać bieżący katalog roboczy, a nawet umożliwia otwieranie plików za pomocą względnych ścieżek plików ...
źródło
Odpowiedzi:
Nie ma niezawodnego sposobu na zrobienie tego w czystej Javie. Ustawienie
user.dir
właściwości za pośrednictwemSystem.setProperty()
lubjava -Duser.dir=...
wydaje się mieć wpływ na kolejne kreacjeFiles
, ale nie npFileOutputStreams
.File(String parent, String child)
Konstruktor może pomóc, jeśli budować swoją ścieżkę oddzielnie od ścieżki do pliku, co umożliwia łatwiejsze swapping.Alternatywą jest skonfigurowanie skryptu do uruchamiania Javy z innego katalogu lub użycie natywnego kodu JNI, jak zasugerowano poniżej .
Odpowiedni błąd Sun został zamknięty w 2008 roku jako „nie zostanie naprawiony”.
źródło
new FileOutputStream("foo.txt").close();
tworzy plik w oryginalnym katalogu roboczym, nawet jeśli plik user.dir zostanie zmieniony przez program.Jeśli uruchomisz swój starszy program z ProcessBuilder , będziesz mógł określić jego katalog roboczy .
źródło
Nie jest to sposób, aby to zrobić za pomocą właściwości systemu „user.dir”. Kluczową kwestią do zrozumienia jest to, że należy wywołać metodę getAbsoluteFile () (jak pokazano poniżej), w przeciwnym razie ścieżki względne zostaną rozstrzygnięte na podstawie domyślnej wartości „user.dir”.
źródło
user.dir
. Dowodzi tego fakt, że ścieżka absolutna staje się krytyczna.Możliwa jest zmiana PWD przy użyciu JNA / JNI do wykonywania wywołań libc. Faceci z JRuby mają przydatną bibliotekę java do wykonywania wywołań POSIX o nazwie jna-posix Oto informacje o maven
Możesz zobaczyć przykład jego użycia tutaj (kod Clojure, przepraszam). Spójrz na funkcję chdirToRoot
źródło
user.dir
właściwości systemowej,File.getAbsolutePath()
zostanie rozwiązane przeciwkouser.dir
, podczas gdy nazwa ścieżki w pliku zostanie rozpoznana w katalogu roboczym systemu operacyjnego.Jak wspomniano, nie możesz zmienić CWD maszyny JVM, ale jeśli chcesz uruchomić inny proces za pomocą Runtime.exec (), możesz użyć przeciążonej metody, która pozwala określić katalog roboczy. Nie służy to tak naprawdę do uruchamiania programu Java w innym katalogu, ale w wielu przypadkach, gdy trzeba uruchomić inny program, na przykład skrypt Perla, można określić katalog roboczy tego skryptu, pozostawiając niezmieniony katalog roboczy maszyny JVM.
Zobacz Runtime.exec javadocs
Konkretnie,
gdzie
dir
jest katalog roboczy, w którym ma zostać uruchomiony podprocesźródło
Jeśli dobrze rozumiem, program Java zaczyna się od kopii aktualnych zmiennych środowiskowych. Wszelkie zmiany za pośrednictwem
System.setProperty(String, String)
modyfikują kopię, a nie oryginalne zmienne środowiskowe. Nie chodzi o to, że dostarcza to dokładnego powodu, dla którego Sun wybrał takie zachowanie, ale być może rzuca trochę światła ...źródło
-D
. Ale zgadzam się, że w JVM uruchamianie predefiniowanych właściwości, takich jakuser.dir
skopiowanie z systemu operacyjnego i ich późniejsza zmiana, nie pomaga.user.dir
wpływaFile.getAbsolutePath()
iFile.getCanonicalPath()
, ale nie na pomysł systemu operacyjnego dotyczący katalogu roboczego, który dyktuje sposób rozwiązywania nazw ścieżek plików podczas uzyskiwania dostępu do plików.Katalog roboczy jest funkcją systemu operacyjnego (ustawianą podczas uruchamiania procesu). Dlaczego po prostu nie przekażesz własnej właściwości System (
-Dsomeprop=/my/path
) i nie użyjesz jej w swoim kodzie jako elementu nadrzędnego pliku:źródło
Sprytniejszą / łatwiejszą rzeczą do zrobienia jest po prostu zmiana kodu, aby zamiast otwierać plik, zakładając, że istnieje w bieżącym katalogu roboczym (zakładam, że robisz coś takiego
new File("blah.txt")
, po prostu sam zbuduj ścieżkę do pliku.Pozwól użytkownikowi przejść do katalogu podstawowego, przeczytaj go z pliku konfiguracyjnego, cofnij się,
user.dir
jeśli inne właściwości nie mogą zostać znalezione itp. Ale o wiele łatwiej jest poprawić logikę w programie niż zmienić sposób zmienne środowiskowe działają.źródło
Próbowałem przywołać
String oldDir = System.setProperty("user.dir", currdir.getAbsolutePath());
Wydaje się, że działa. Ale
File myFile = new File("localpath.ext"); InputStream openit = new FileInputStream(myFile);
rzuca
FileNotFoundException
choćmyFile.getAbsolutePath()
pokazuje poprawną ścieżkę. Mam to przeczytać . Myślę, że problem jest taki:
Rozwiązaniem może być:
File myFile = new File(System.getPropety("user.dir"), "localpath.ext");
Tworzy obiekt plikowy jako absolutny z bieżącym katalogiem, który jest znany maszynie JVM. Ale ten kod powinien istnieć w używanej klasie, wymaga zmiany kodów ponownie używanych.
~~~~ JcHartmut
źródło
Możesz użyć
po
Wydrukuje
źródło
System.setProperty("user.dir", "/some/directory")
Inna możliwa odpowiedź na to pytanie może zależeć od powodu, dla którego otwierasz plik. Czy jest to plik właściwości czy plik, który ma konfigurację związaną z Twoją aplikacją?
W takim przypadku możesz rozważyć próbę załadowania pliku przez program ładujący ścieżki klas, w ten sposób możesz załadować dowolny plik, do którego Java ma dostęp.
źródło
Jeśli uruchamiasz swoje polecenia w powłoce, możesz napisać coś takiego jak „java -cp” i dodać dowolne katalogi, które chcesz oddzielone znakiem „:”. Jeśli java nie znajdzie czegoś w jednym katalogu, spróbuje znaleźć je w innych katalogach, jest tym, co robię.
źródło
Możesz zmienić rzeczywisty katalog roboczy procesu za pomocą JNI lub JNA.
Dzięki JNI możesz używać natywnych funkcji do ustawiania katalogu. Metoda POSIX to
chdir()
. W systemie Windows możesz użyćSetCurrentDirectory()
.Dzięki JNA możesz opakować natywne funkcje w bindery Java.
Dla Windowsa:
Dla systemów POSIX:
źródło
Użyj FileSystemView
źródło