Java'da geçerli çalışma dizini değiştiriliyor mu?


169

Geçerli çalışma dizinini bir Java programı içinden nasıl değiştirebilirim? Sorun hakkında bulabildiğim her şey, bunu yapamayacağınızı iddia ediyor, ancak bunun gerçekten böyle olduğuna inanamıyorum.

Normalde başladığı dizinden sabit kodlu göreceli dosya yolu kullanarak bir dosyayı açan bir kod parçam var ve sadece o kodu farklı bir Java programından içinden başlatmak zorunda kalmadan kullanabilmek istiyorum belirli bir dizin. Görünüşe göre sadece arayabiliyor olmalısın System.setProperty( "user.dir", "/path/to/dir" ), ama anlayabildiğim kadarıyla, bu hattı çağırmak sessizce başarısız oluyor ve hiçbir şey yapmıyor.

Java bunu yapmak izin vermedi eğer sen izin vermesinden olmasaydı, anlardın olsun ...., geçerli çalışma dizini ve hatta nispi dosya yollarını kullanarak açık dosyalara izin verir


1
Bilgi almak ve kullanmak, bilgiyi değiştirmekten farklıdır. Örneğin Windows'da ortam değişkenlerini kolayca alabilirsiniz, ancak bunları değiştirmek daha zordur (sistem genelinde).
PhiLho

1
bugs.java.com/bugdatabase/view_bug.do?bug_id=4045688 "O zamandan beri başka müşteri öne çıkmadı veya başka bir şekilde tanımlanmadı." adlı değerlendirme bölümünde belirtiliyor ve 2018'den itibaren yaklaşık 175.000 var Bu sorunun görüntülenmesi :-(
Wolfgang Fahl

Yanıtlar:


146

Bunu saf Java ile yapmanın güvenilir bir yolu yoktur. Özelliğin veya user.diryoluyla ayarlanması, sonraki oluşturmalarını etkiler , ancak örn .System.setProperty()java -Duser.dir=...FilesFileOutputStreams

File(String parent, String child)Eğer daha kolay takas sağlayan, dosya yolundan ayrı dizin yolunu kurmak eğer yapıcı yardımcı olabilir.

Alternatif olarak, Java'yı farklı bir dizinden çalıştırmak için bir komut dosyası ayarlamak ya da aşağıda önerildiği gibi JNI yerel kodunu kullanmaktır .

İlgili Sun hatası 2008'de "düzeltilmeyecek" olarak kapatıldı.


12
Java ve c # arasında tek bir fark bulduğumu sanmıyorum, bu beni düşündürüyor, "bu java çocuklar ne yaptıklarını kesinlikle biliyorlar"
Jake


5
Java'nın savunmasında (ve ben bu özelliği isteyen bir UNIX adamıyım) ... OS ayrıntılarına karşı agnostik olması gereken bir VM. "Mevcut çalışma dizini" deyimi bazı işletim sistemlerinde bulunmaz.
Tony K.

4
Java'ya karşı adil olmak için önce bunu yapmak zorundaydılar, C # birçok alanda hatalarından öğrenebilme avantajına sahipti.
Ryan The Leach

3
@VolkerSeibt: Daha fazla araştırma yapıldığında, user.dir'in ilk başta test ettiğim sınıf da dahil olmak üzere sadece bazı sınıflar için çalıştığı görülüyor. new FileOutputStream("foo.txt").close();user.dir program tarafından değiştirilse bile dosyayı özgün çalışma dizininde oluşturur.
Michael Myers

37

Eski programınızı ProcessBuilder ile çalıştırırsanız , çalışma dizinini belirtebilirsiniz .


1
rotası benim izlediğim rota. Aşağıdaki ile farklı bir çalışma dizininden yürütülebilir bir çalıştırmak mümkün: Dosya WorkingDir = yeni Dosya ("C: \\ yol \\ \\ çalışma \\ dir \\"); ProcessBuilder pBuilder = new ProcessBuilder ("C: \\ yol \\ - \\ çalışma \\ dir \\ yürütülebilir.exe"); pBuilder.directory (WORKINGDIR); İşlem p = pBuilder.start ();
CatsAndCode

29

Orada bir sistem özelliği "user.dir" seçeneğini kullanarak bunu yapmanın bir yolu. Anlaşılması gereken kilit kısım, getAbsoluteFile () işlevinin (aşağıda gösterildiği gibi) çağrılması gerektiğidir, aksi takdirde göreli yollar varsayılan "user.dir" değerine göre çözümlenecektir .

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");
    }
}

3
mutlak yol önemlidir
HackNone

5
Ancak geçerli çalışma dizinini değiştirmez. Yalnızca değeri user.dir. Mutlak yolun kritik hale gelmesi bunu kanıtlar.
Lorne Marquis

18

Libc çağrıları yapmak için JNA / JNI kullanarak PWD değiştirmek mümkündür. JRuby çocuklar jna-posix denilen POSIX çağrıları yapmak için kullanışlı bir java kütüphanesi var İşte maven bilgisi

Kullanımının bir örneğini burada görebilirsiniz (Clojure kodu, üzgünüm). ChdirToRoot işlevine bakın


1
Jna-posix'in modern bir versiyonu yok gibi görünüyor. Çatalladım ve ekledim: github.com/pbiggar/jnr-posix . Bununla PWD'yi değiştirebileceğimi doğrulayabilirim.
Paul Biggar

Evet. Maalesef, bu dosyayı yeniden düzenledim ve dosyaya bağlı bu yanıtı unuttum. Sabit.
Allen Rohner

Bunu yapabilirsin, ama aynı zamanda değiştirmezseniz user.dirsistem özelliği daha sonra File.getAbsolutePath()karşı çözecektir user.dirOS karşı Dosya giderir içinde yol adı dizini çalışırken,.
Morrie

Orijinal soru ile ilgili olarak, jnr-posix kullanarak, Java'daki geçerli çalışma dizinini nasıl değiştirebilirim. Chdir yöntemini kullanmak için hangi sınıfı kullanmam gerekir? Verilen Clojure örneğini gerçekten anlamadım. Şimdiden teşekkürler.
Sam Saint-Pettersen

12

Belirtildiği gibi, JVM'nin CWD'sini değiştiremezsiniz, ancak Runtime.exec () kullanarak başka bir işlem başlatacaksanız, çalışma dizinini belirtmenize izin veren aşırı yüklenmiş yöntemi kullanabilirsiniz. Bu, Java programınızı başka bir dizinde çalıştırmak için değil, örneğin Perl betiği gibi başka bir programı başlatmanız gerektiğinde, JVM'nin çalışma dizinini değiştirmeden bu komut dosyasının çalışma dizinini belirtebilirsiniz.

Bkz. Runtime.exec javadocs

özellikle,

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

diriçinde alt süreci çalıştıracak çalışma dizini nerede


1
Bu, kabul edilen yanıttan daha iyi bir yanıt gibi görünüyor (ki bu "Saf Java'da bunu yapmanın güvenilir bir yolu yoktur."). Bu cevabın kabul edilen cevap olarak kabul edilmesi için dilekçe vermenin bir yolu var mı?
John

11

Doğru anlarsam, Java programı geçerli ortam değişkenlerinin bir kopyasıyla başlar . Yoluyla System.setProperty(String, String)yapılan değişiklikler orijinal ortam değişkenlerini değil kopyayı değiştirir. Bu, Sun'ın bu davranışı neden seçtiğine dair kapsamlı bir neden sağladığından değil, belki de biraz ışık tutuyor ...


2
Ortam değişkenlerini ve özelliklerini karıştırıyor gibisiniz. Bunlardan birincisi işletim sisteminden devralınırken ikincisi komut satırında kullanılarak tanımlanabilir -D. Ancak, JVM başlangıçta user.dirişletim sisteminden kopyalanın ve daha sonra bunları değiştirmek gibi önceden tanımlanmış özellikleri yardımcı olmamaya katılıyorum .
maaartinus

Değişiklik , işletim sisteminin dosyalara erişirken Dosya yol adlarının nasıl çözümlendiğini belirleyen çalışma dizini fikrini user.diretkiler File.getAbsolutePath()ve etkilemez File.getCanonicalPath().
Morrie

5

Çalışma dizini bir işletim sistemi özelliğidir (işlem başladığında ayarlanır). Neden sadece kendi System mülkünüzü ( -Dsomeprop=/my/path) geçmiyor ve bunu kodunuzda Dosyanızın üst öğesi olarak kullanmıyorsunuz:

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

Kod parçası sabit kodlu bir dosya yolu içerdiğinden ve muhtemelen çalışılacak üst dizini belirtmeyen sabit kodlu bir kurucu kullandığından. En azından, sahip olduğum durum bu :)
David Mann

4

Burada yapmak için daha akıllı / daha kolay bir şey sadece geçerli çalışma dizinde var olduğunu varsayarak dosyayı açmak yerine kodunuzu değiştirmek için (Ben böyle bir şey yapıyoruz varsayalım new File("blah.txt"), sadece dosyanın yolunu kendiniz oluşturmak.

Kullanıcının temel dizinden geçmesine izin verin, bir yapılandırma dosyasından okuyun user.dir, diğer özelliklerin bulunamaması durumunda geri dönün, ancak programınızdaki mantığı geliştirmek, nasıl değiştirildiğinden çok daha kolaydır. ortam değişkenleri.


2

Çağırmaya çalıştım

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

İşe yarıyor gibi görünüyor. Fakat

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

FileNotFoundExceptionolsa atar

myFile.getAbsolutePath()

doğru yolu gösterir. Bunu okudum . Bence sorun şu:

  • Java geçerli dizini yeni ayarla bilir.
  • Ancak dosya işleme işletim sistemi tarafından yapılır. Ne yazık ki, yeni ayarlanmış geçerli dizini bilmiyor.

Çözüm şu olabilir:

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

JVM tarafından bilinen geçerli dizine mutlak bir dosya nesnesi oluşturur. Ancak bu kod kullanılmış bir sınıfta mevcut olmalıdır, yeniden kullanılan kodların değiştirilmesi gerekir.

~~~~ JcHartmut


Msgstr "Bir dosya nesnesi oluşturur" - evet. Ancak dosya sisteminde bir dosya oluşturmaz. Bundan sonra file.createNewFile () yöntemini kullanmayı unuttunuz.
Gangnus

2

Kullanabilirsiniz

yeni Dosya ("göreceli / yol"). getAbsoluteFile ()

sonra

System.setProperty ("kullanıcı.dir", "/ bazı / dizin")

System.setProperty("user.dir", "C:/OtherProject");
File file = new File("data/data.csv").getAbsoluteFile();
System.out.println(file.getPath());

Yazdırılacak

C:\OtherProject\data\data.csv

1
Java 11'de bu davranışın değiştiğini lütfen unutmayın, bugs.openjdk.java.net/browse/JDK-8202127 adresine bakın . Kullanmayı tavsiye etmiyorlarSystem.setProperty("user.dir", "/some/directory")
Martin

0

Bu soruya verilebilecek diğer olası yanıt, dosyayı açma nedeninize bağlı olabilir. Bu bir özellik dosyası mı yoksa uygulamanızla ilgili bir yapılandırmaya sahip bir dosya mı?

Bu durumda, dosyayı sınıf yolu yükleyicisiyle yüklemeyi denemeyi düşünebilirsiniz, bu şekilde Java'nın erişebildiği herhangi bir dosyayı yükleyebilirsiniz.


0

Komutlarınızı bir kabukta çalıştırırsanız, "java -cp" gibi bir şey yazabilir ve ":" ile ayrılmış istediğiniz dizinleri ekleyebilirsiniz. yaptığım şey bu.


0

JNI veya JNA kullanarak işlemin gerçek çalışma dizinini değiştirebilirsiniz.

JNI ile, dizini ayarlamak için yerel işlevleri kullanabilirsiniz. POSIX yöntemi chdir(). Windows'da kullanabilirsiniz SetCurrentDirectory().

JNA ile, yerel işlevleri Java bağlayıcılarına sarabilirsiniz.

Pencereler için:

private static interface MyKernel32 extends Library {
    public MyKernel32 INSTANCE = (MyKernel32) Native.loadLibrary("Kernel32", MyKernel32.class);

    /** BOOL SetCurrentDirectory( LPCTSTR lpPathName ); */
    int SetCurrentDirectoryW(char[] pathName);
}

POSIX sistemleri için:

private interface MyCLibrary extends Library {
    MyCLibrary INSTANCE = (MyCLibrary) Native.loadLibrary("c", MyCLibrary.class);

    /** int chdir(const char *path); */
    int chdir( String path );
}

-1

FileSystemView Kullan

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

import javax.swing.filechooser.FileSystemView;
Borneq

1
Bu cevap soru ile ilgili değildir.
Aaron Digulla
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.