Baca file properti di luar file JAR

131

Saya memiliki file JAR di mana semua kode saya diarsipkan untuk dijalankan. Saya harus mengakses file properti yang perlu diubah / diedit sebelum setiap kali dijalankan. Saya ingin menyimpan file properti di direktori yang sama di mana file JAR. Apakah ada cara untuk memberi tahu Java untuk mengambil file properti dari direktori itu?

Catatan: Saya tidak ingin menyimpan file properti di direktori home atau melewatkan path file properti dalam argumen baris perintah.

Neil
sumber
2
Lihat jawaban ini - "Alih-alih menyimpan file 'default' di dalam Jar. Jika diubah, simpan file yang diubah di tempat lain. Satu tempat yang umum adalah sub-direktori user.home. Saat memeriksa file, pertama-tama periksa keberadaan file yang diubah pada sistem file, dan jika tidak ada, muat file default. " BTW "Saya tidak mau .." Apa yang Anda inginkan kurang penting daripada apa yang berhasil dan praktis. Menyimpan aplikasi. pengaturan dalam direktori aplikasi sangat tidak disarankan oleh Oracle & MS (& mungkin yang lain).
Andrew Thompson
3
Alasan mengapa saya perlu menyimpan file properti di direktori jar adalah bahwa lebih baik menyimpannya bersama ketika seluruh direktori (termasuk jar dan properti) disalin ke mesin lain dan dijalankan.
Neil
Dan jika saya memaksa pengguna untuk melewati path file properti maka dia perlu mengubahnya setiap kali dia menjalankan file batch dari mesin yang berbeda.
Neil

Jawaban:

144

Jadi, Anda ingin memperlakukan .propertiesfile Anda pada folder yang sama dengan jar utama / runnable sebagai file daripada sebagai sumber daya dari jar utama / runnable. Dalam hal ini, solusi saya sendiri adalah sebagai berikut:

Hal pertama yang pertama: arsitektur file program Anda akan seperti ini (dengan asumsi program utama Anda adalah main.jar dan file properti utamanya adalah main.properties):

./ - the root of your program
 |__ main.jar
 |__ main.properties

Dengan arsitektur ini, Anda dapat memodifikasi properti apa pun di file properti utama menggunakan editor teks apa pun sebelum atau saat main.jar Anda berjalan (tergantung pada kondisi program saat ini) karena itu hanya file berbasis teks. Misalnya, file properti utama Anda mungkin berisi:

app.version=1.0.0.0
app.name=Hello

Jadi, ketika Anda menjalankan program utama dari folder root / base-nya, biasanya Anda akan menjalankannya seperti ini:

java -jar ./main.jar

atau, langsung:

java -jar main.jar

Di main.jar Anda, Anda perlu membuat beberapa metode utilitas untuk setiap properti yang ditemukan di file properti utama Anda; katakanlah app.versionproperti akan memiliki getAppVersion()metode sebagai berikut:

/**
 * Gets the app.version property value from
 * the ./main.properties file of the base folder
 *
 * @return app.version string
 * @throws IOException
 */

import java.util.Properties;

public static String getAppVersion() throws IOException{

    String versionString = null;

    //to load application's properties, we use this class
    Properties mainProperties = new Properties();

    FileInputStream file;

    //the base folder is ./, the root of the main.properties file  
    String path = "./main.properties";

    //load the file handle for main.properties
    file = new FileInputStream(path);

    //load all the properties from this file
    mainProperties.load(file);

    //we have loaded the properties, so close the file handle
    file.close();

    //retrieve the property we are intrested, the app.version
    versionString = mainProperties.getProperty("app.version");

    return versionString;
}

Di bagian mana pun dari program utama yang membutuhkan app.versionnilai, kami menyebut metodenya sebagai berikut:

String version = null;
try{
     version = getAppVersion();
}
catch (IOException ioe){
    ioe.printStackTrace();
}
ecle
sumber
7
Solusi ini berfungsi. Terima kasih telah memahami persyaratan yang tepat dan kode terperinci. Saya memverifikasi bahwa file properti tidak ada di dalam file jar tetapi masih dapat mengakses file dari direktori yang sama di mana file jar berada. Dengan cara ini tidak diperlukan kode keras jalur absolut. File jar dan properti sekarang dapat disalin ke direktori mana pun dan berjalan secara independen.
Neil
3
File tidak akan ditemukan jika Anda menjalankan perintah dari luar untuk ex: {{java -jar build / main.jar}}. Apakah Anda punya perbaikan untuk itu, @ ya?
Darian
@Darian Tidak ada yang diperbaiki di sini; Ini hanya berfungsi seperti yang dirancang di mana jar dan file properti harus berada di ./folder root yang sama (level direktori yang sama) seperti apa yang telah saya jelaskan dalam arsitektur organisasi file. (sesuai kebutuhan yang ditetapkan oleh poster asli)
ecle
@Darian, jadi jika Anda ingin mengeksekusi java -jar build/main.jar, Anda perlu meletakkan file properti di buildfolder juga sehingga berada pada level direktori yang sama dengan toples.
ecle
7
Terima kasih atas tanggapan Anda @ ya, masalahnya adalah saya tidak tahu di mana pengguna akan menjalankan java -jar path/to/jar/file. Tapi saya menemukan solusinya dalam pertanyaan lain:String path = ClassLoader.getSystemClassLoader().getResource(".").getPath() + "/main.properties";
Darian
42

Saya melakukannya dengan cara lain.

Properties prop = new Properties();
    try {

        File jarPath=new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
        String propertiesPath=jarPath.getParentFile().getAbsolutePath();
        System.out.println(" propertiesPath-"+propertiesPath);
        prop.load(new FileInputStream(propertiesPath+"/importer.properties"));
    } catch (IOException e1) {
        e1.printStackTrace();
    }
  1. Dapatkan jalur file Jar.
  2. Dapatkan folder Induk dari file itu.
  3. Gunakan jalur itu di InputStreamPath dengan nama file properti Anda.
Ninad Pingale
sumber
Saya harus menghapus bagian getParentFile () jadi saya menggunakan: String propertiesPath = jarPath.getAbsolutePath (); tetapi semuanya tergantung pada di mana file tersebut berada
MobileMon
4
Cukup Ganti "jarPath.getParentFile (). GetAbsolutePath ();" ke "jarPath.getParent ()". Berfungsi seperti pesona.
StackAddict
1
Sama adalah Masalah dalam kasus saya tetapi saya memiliki proyek pangkalan. Bagaimana cara memberitahu pegas bahwa file itu di sebelah file jar? ide apa pun
Mubasher
3

Selalu ada masalah mengakses file di direktori file Anda dari file jar. Menyediakan classpath dalam file jar sangat terbatas. Alih-alih mencoba menggunakan file bat atau file sh untuk memulai program Anda. Dengan cara itu Anda dapat menentukan classpath Anda sesuai keinginan Anda, merujuk folder apa pun di sistem.

Periksa juga jawaban saya untuk pertanyaan ini:

membuat file .exe untuk proyek java yang berisi sqlite

sethu
sumber
1

Saya memiliki kasus serupa: menginginkan *.jarfile saya untuk mengakses file di direktori di sebelah *.jarfile tersebut. Lihat juga JAWABAN INI .

Struktur file saya adalah:

./ - the root of your program
|__ *.jar
|__ dir-next-to-jar/some.txt

Saya dapat memuat file (katakanlah some.txt) ke InputStream di dalam *.jarfile dengan yang berikut:

InputStream stream = null;
    try{
        stream = ThisClassName.class.getClass().getResourceAsStream("/dir-next-to-jar/some.txt");
    }
    catch(Exception e) {
        System.out.print("error file to stream: ");
        System.out.println(e.getMessage());
    }

Kemudian lakukan apa pun yang Anda mau dengan stream

ddaaggeett
sumber
0

Saya punya contoh melakukan keduanya dengan classpath atau dari konfigurasi eksternal dengan log4j2.properties

package org.mmartin.app1;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.LogManager;


public class App1 {
    private static Logger logger=null; 
    private static final String LOG_PROPERTIES_FILE = "config/log4j2.properties";
    private static final String  CONFIG_PROPERTIES_FILE = "config/config.properties";

    private Properties properties= new Properties();

    public App1() {
        System.out.println("--Logger intialized with classpath properties file--");
        intializeLogger1();
        testLogging();
        System.out.println("--Logger intialized with external file--");
        intializeLogger2();
        testLogging();
    }




    public void readProperties()  {
        InputStream input = null;
        try {
            input = new FileInputStream(CONFIG_PROPERTIES_FILE);
            this.properties.load(input);
        } catch (IOException e) {
            logger.error("Unable to read the config.properties file.",e);
            System.exit(1);
        }
    }

    public void printProperties() {
        this.properties.list(System.out);
    }

    public void testLogging() {
        logger.debug("This is a debug message");
        logger.info("This is an info message");
        logger.warn("This is a warn message");
        logger.error("This is an error message");
        logger.fatal("This is a fatal message");
        logger.info("Logger's name: "+logger.getName());
    }


    private void intializeLogger1() {
        logger = LogManager.getLogger(App1.class);
    }
    private void intializeLogger2() {
        LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
        File file = new File(LOG_PROPERTIES_FILE);
        // this will force a reconfiguration
        context.setConfigLocation(file.toURI());
        logger = context.getLogger(App1.class.getName());
    }

    public static void main(String[] args) {
        App1 app1 = new App1();
        app1.readProperties();
        app1.printProperties();
    }
}


--Logger intialized with classpath properties file--
[DEBUG] 2018-08-27 10:35:14.510 [main] App1 - This is a debug message
[INFO ] 2018-08-27 10:35:14.513 [main] App1 - This is an info message
[WARN ] 2018-08-27 10:35:14.513 [main] App1 - This is a warn message
[ERROR] 2018-08-27 10:35:14.513 [main] App1 - This is an error message
[FATAL] 2018-08-27 10:35:14.513 [main] App1 - This is a fatal message
[INFO ] 2018-08-27 10:35:14.514 [main] App1 - Logger's name: org.mmartin.app1.App1
--Logger intialized with external file--
[DEBUG] 2018-08-27 10:35:14.524 [main] App1 - This is a debug message
[INFO ] 2018-08-27 10:35:14.525 [main] App1 - This is an info message
[WARN ] 2018-08-27 10:35:14.525 [main] App1 - This is a warn message
[ERROR] 2018-08-27 10:35:14.525 [main] App1 - This is an error message
[FATAL] 2018-08-27 10:35:14.525 [main] App1 - This is a fatal message
[INFO ] 2018-08-27 10:35:14.525 [main] App1 - Logger's name: org.mmartin.app1.App1
-- listing properties --
dbpassword=password
database=localhost
dbuser=user
pitchblack408
sumber
0

Ini bekerja untuk saya. Muat file properti Anda daricurrent directory

Properties properties = new Properties();
properties.load(new FileReader(new File(".").getCanonicalPath() + File.separator + "java.properties"));
properties.forEach((k, v) -> {
            System.out.println(k + " : " + v);
        });

Pastikan, itu java.propertiesada di current directory. Anda bisa menulis skrip startup kecil yang beralih ke direktori yang benar sebelumnya, seperti

#! /bin/bash
scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 
cd $scriptdir
java -jar MyExecutable.jar
cd -

Dalam proyek Anda, cukup letakkan java.propertiesfile di root proyek Anda, untuk membuat kode ini bekerja dari IDE Anda juga.

Jschnasse
sumber
0

Di sini, jika Anda menyebutkan .getPath()bahwa itu akan mengembalikan jalur Jar dan saya kira Anda akan membutuhkan induknya untuk merujuk ke semua file konfigurasi lainnya yang ditempatkan dengan jar. Kode ini berfungsi di Windows. Tambahkan kode di dalam kelas utama.

File jarDir = new File(MyAppName.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String jarDirpath = jarDir.getParent();

System.out.println(jarDirpath);
Sarangz
sumber