Modifica della directory di lavoro corrente in Java?

Come posso cambiare la directory di lavoro corrente da un programma Java? Tutto quello che sono stato in grado di trovare sul problema afferma che semplicemente non puoi farlo, ma non posso credere che sia proprio così.

Ho un pezzo di codice che apre un file usando un percorso di file relativo hard-coded dalla directory in cui è normalmente avviato, e voglio solo essere in grado di usare quel codice all’interno di un diverso programma Java senza doverlo avviare dall’interno una directory particolare. Sembra che dovresti essere in grado di chiamare System.setProperty( "user.dir", "/path/to/dir" ) , ma per quanto posso capire, chiamare quella linea fallisce silenziosamente e non fa nulla.

Capirei se Java non ti permettesse di farlo, se non fosse per il fatto che ti permette di ottenere la directory di lavoro corrente e persino di aprire i file usando percorsi di file relativi ….

Non esiste un modo affidabile per farlo in puro Java. L’impostazione della proprietà user.dir tramite System.setProperty() o java -Duser.dir=... sembra influire sulle successive creazioni di Files , ma non su FileOutputStreams .

Il costruttore File(String parent, String child) può essere d’aiuto se si crea il percorso della directory separatamente dal percorso del file, consentendo uno scambio più facile.

Un’alternativa è impostare uno script per eseguire Java da una directory diversa o utilizzare il codice nativo JNI come suggerito di seguito .

Il bug Sun pertinente è stato chiuso nel 2008 come “non risolverà”.

Se esegui il tuo programma legacy con ProcessBuilder , sarai in grado di specificare la sua directory di lavoro.

C’è un modo per farlo usando la proprietà di sistema “user.dir”. La parte fondamentale da comprendere è che getAbsoluteFile () deve essere chiamato (come mostrato di seguito), altrimenti i percorsi relativi verranno risolti rispetto al valore predefinito “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"); } } 

È ansible modificare il PWD, usando JNA / JNI per effettuare chiamate a libc. I ragazzi di JRuby hanno una comoda libreria java per effettuare chiamate POSIX chiamate jna-posix Ecco le informazioni di carattere

Puoi vedere un esempio del suo uso qui (codice Clojure, mi dispiace). Guarda la funzione chdirToRoot

Se ho capito bene, un programma Java inizia con una copia delle variabili di ambiente correnti. Qualsiasi modifica tramite System.setProperty(String, String) sta modificando la copia, non le variabili di ambiente originali. Non che questo fornisca una spiegazione approfondita del motivo per cui Sun ha scelto questo comportamento, ma forse getta un po ‘di luce …

Come accennato, non è ansible modificare il CWD della JVM, ma se si dovesse avviare un altro processo utilizzando Runtime.exec () è ansible utilizzare il metodo sovraccarico che consente di specificare la directory di lavoro. Questo non è proprio per l’esecuzione del programma Java in un’altra directory, ma per molti casi, quando è necessario lanciare un altro programma come uno script Perl, è ansible specificare la directory di lavoro di quello script lasciando invariata la directory di lavoro della JVM.

Vedi javadocs di Runtime.exec

In particolare,

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

dove dir è la directory di lavoro per eseguire il sottoprocesso in

La directory di lavoro è una funzione del sistema operativo (impostata all’avvio del processo). Perché non passi semplicemente la tua proprietà di sistema ( -Dsomeprop=/my/path ) e la usi nel tuo codice come genitore del tuo file:

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

La cosa più intelligente / più facile da fare qui è cambiare semplicemente il tuo codice in modo che invece di aprire il file supponendo che esista nella directory di lavoro corrente (presumo tu stia facendo qualcosa come il new File("blah.txt") , basta build il percorso per il file te stesso.

Consenti all’utente di passare nella directory di base, leggerlo da un file di configurazione, tornare a user.dir se non è ansible trovare altre proprietà, ecc. Ma è molto più semplice migliorare la logica nel tuo programma che non per cambiare il funzionamento delle variabili di ambiente.

Ho provato a invocare

String oldDir = System.setProperty("user.dir", currdir.getAbsolutePath());

Sembra funzionare. Ma

File myFile = new File("localpath.ext"); InputStream openit = new FileInputStream(myFile);

tuttavia lancia una FileNotFoundException

myFile.getAbsolutePath()

mostra il percorso corretto. Ho letto questo . Penso che il problema sia:

  • Java conosce la directory corrente con la nuova impostazione.
  • Ma la gestione dei file viene eseguita dal sistema operativo. Sfortunatamente non conosce la nuova directory corrente impostata.

La soluzione potrebbe essere:

File myFile = new File(System.getPropety("user.dir"), "localpath.ext");

Crea un file Object come assoluto con la directory corrente che è conosciuta da JVM. Ma quel codice dovrebbe essere esistente in una class usata, ha bisogno di cambiare i codici riutilizzati.

~~~~ JcHartmut

Puoi usare

nuovo file (“relativo / percorso”). getAbsoluteFile ()

dopo

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

Stamperà

 C:\OtherProject\data\data.csv 

L’altra ansible risposta a questa domanda può dipendere dal motivo per cui si sta aprendo il file. Si tratta di un file di proprietà o di un file con qualche configurazione correlata alla tua applicazione?

Se questo è il caso, puoi provare a caricare il file attraverso il loader del classpath, in questo modo puoi caricare qualsiasi file a cui Java abbia accesso.

Se si eseguono i comandi in una shell, è ansible scrivere qualcosa come “java -cp” e aggiungere qualsiasi directory che si desidera separare da “:” se java non trova qualcosa in una directory andrà a cercare e trovarli nelle altre directory, che è quello che faccio

Usa FileSystemView

 private FileSystemView fileSystemView; fileSystemView = FileSystemView.getFileSystemView(); currentDirectory = new File("."); //listing currentDirectory File[] filesAndDirs = fileSystemView.getFiles(currentDirectory, false); fileList = new ArrayList(); dirList = new ArrayList(); 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);