53

I have a file called mybundle.txt in c:/temp -

c:/temp/mybundle.txt

How do I load this file into a java.util.ResourceBundle? The file is a valid resource bundle.

This does not seem to work:

java.net.URL resourceURL = null;

String path = "c:/temp/mybundle.txt";
java.io.File fl = new java.io.File(path);

try {
   resourceURL = fl.toURI().toURL();
} catch (MalformedURLException e) {             
}           

URLClassLoader urlLoader = new URLClassLoader(new java.net.URL[]{resourceURL});
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle( path , 
                java.util.Locale.getDefault(), urlLoader );
Jared Harley
  • 8,219
  • 4
  • 39
  • 48

14 Answers14

79

As long as you name your resource bundle files correctly (with a .properties extension), then this works:

File file = new File("C:\\temp");
URL[] urls = {file.toURI().toURL()};
ClassLoader loader = new URLClassLoader(urls);
ResourceBundle rb = ResourceBundle.getBundle("myResource", Locale.getDefault(), loader);

where "c:\temp" is the external folder (NOT on the classpath) holding the property files, and "myResource" relates to myResource.properties, myResource_fr_FR.properties, etc.

Credit to http://www.coderanch.com/t/432762/java/java/absolute-path-bundle-file

Forge_7
  • 1,839
  • 2
  • 20
  • 19
51

When you say it's "a valid resource bundle" - is it a property resource bundle? If so, the simplest way of loading it probably:

try (FileInputStream fis = new FileInputStream("c:/temp/mybundle.txt")) {
  return new PropertyResourceBundle(fis);
}
spongebob
  • 8,370
  • 15
  • 50
  • 83
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    Hey Jon, doesn't this miss the localization issue that would be the main reason for using a bundle in the first place? – Nick Holt Jul 23 '09 at 16:29
  • 3
    There's no indication that he's actually got more than one file. The fact that it's got a .txt suffix isn't terribly encouraging. But yes, it would fail in that situation. – Jon Skeet Jul 23 '09 at 16:45
  • 9
    Rather than loading a file manually (i.e. with `FileInputStream`) and constructing a `ProperyResourceBundle`, should't the "right way" be to use the `ResourceBundle.getBundle(...)` method? – Vihung Feb 24 '12 at 11:51
  • 5
    @Vihung `ResourceBundle.getBundle()` will load a resource bundle from the classpath and using a given Locale. Not the "raw" file as the OP expects. – Matthieu Aug 21 '15 at 13:31
22

1) Change the extension to properties (ex. mybundle.properties.)
2) Put your file into a jar and add it to your classpath.
3) Access the properties using this code:

ResourceBundle rb = ResourceBundle.getBundle("mybundle");
String propertyValue = rb.getString("key");
Eminem
  • 7,206
  • 15
  • 53
  • 95
Ludington
  • 997
  • 9
  • 12
  • This is unfortunately not possible if the jar is embedded in an executable file by Launch4j and such... – Matthieu Aug 21 '15 at 13:32
  • 3
    The property file doesn't have to be inside a JAR. If the class is in a package `a.b.c.MyClass.java`, then `mybundle.properties` has to be in the *parent* folder of `a`, which would be the classpath. I.e. for a class `/myproject/a/b/c/MyClass.java` the resource bundle must be placed in `/myproject/mybundle.properties`. – ccpizza Dec 08 '15 at 20:57
  • I am using Maven. I put the file in the resource folder such as `src/test/resources` or `src/main/resources` and it worked. Then, I found out that it was copied to `target/test-classes` which actually matched your comment. I think this is because the folder `target/test-classes` is part of the classpath. – tarekahf Jan 20 '23 at 17:06
11

From the JavaDocs for ResourceBundle.getBundle(String baseName):

baseName - the base name of the resource bundle, a fully qualified class name

What this means in plain English is that the resource bundle must be on the classpath and that baseName should be the package containing the bundle plus the bundle name, mybundle in your case.

Leave off the extension and any locale that forms part of the bundle name, the JVM will sort that for you according to default locale - see the docs on java.util.ResourceBundle for more info.

Nick Holt
  • 33,455
  • 4
  • 52
  • 58
7

For JSF Application

To get resource bundle prop files from a given file path to use them in a JSF app.

  • Set the bundle with URLClassLoader for a class that extends ResourceBundle to load the bundle from the file path.
  • Specify the class at basename property of loadBundle tag. <f:loadBundle basename="Message" var="msg" />

For basic implementation of extended RB please see the sample at Sample Customized Resource Bundle

/* Create this class to make it base class for Loading Bundle for JSF apps */
public class Message extends ResourceBundle {
        public Messages (){
                File file = new File("D:\\properties\\i18n");  
                ClassLoader loader=null;
                   try {
                       URL[] urls = {file.toURI().toURL()};  
                       loader = new URLClassLoader(urls); 
                       ResourceBundle bundle = getBundle("message", FacesContext.getCurrentInstance().getViewRoot().getLocale(), loader);
                       setParent(bundle);
                       } catch (MalformedURLException ex) { }
       }
      .
      .
      .
    }

Otherwise, get the bundle from getBundle method but locale from others source like Locale.getDefault(), the new (RB)class may not require in this case.

Community
  • 1
  • 1
Jeyan
  • 729
  • 1
  • 14
  • 27
5

If, like me, you actually wanted to load .properties files from your filesystem instead of the classpath, but otherwise keep all the smarts related to lookup, then do the following:

  1. Create a subclass of java.util.ResourceBundle.Control
  2. Override the newBundle() method

In this silly example, I assume you have a folder at C:\temp which contains a flat list of ".properties" files:

public class MyControl extends Control {
@Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
        throws IllegalAccessException, InstantiationException, IOException {

    if (!format.equals("java.properties")) {
        return null;
    }

    String bundleName = toBundleName(baseName, locale);
    ResourceBundle bundle = null;

    // A simple loading approach which ditches the package      
    // NOTE! This will require all your resource bundles to be uniquely named!
    int lastPeriod = bundleName.lastIndexOf('.');

    if (lastPeriod != -1) {
        bundleName = bundleName.substring(lastPeriod + 1);
    }
    InputStreamReader reader = null;
    FileInputStream fis = null;
    try {

        File file = new File("C:\\temp\\mybundles", bundleName);

        if (file.isFile()) { // Also checks for existance
            fis = new FileInputStream(file);
            reader = new InputStreamReader(fis, Charset.forName("UTF-8"));
            bundle = new PropertyResourceBundle(reader);
        }
    } finally {
        IOUtils.closeQuietly(reader);
        IOUtils.closeQuietly(fis);
    }
    return bundle;
}

}

Note also that this supports UTF-8, which I believe isn't supported by default otherwise.

John
  • 1,974
  • 2
  • 25
  • 32
  • Supporting UTF-8 breaks for .properties files that contain non-ASCII ISO-8859-1 characters (codepoints 128-255), which is legal. ISO-8859-1 represent these with one byte each, while UTF-8 uses two bytes for them. – Christoffer Hammarström Feb 27 '14 at 11:50
  • This comment is incorrect. UTF-8 has a variable number of bytes and is the right answer for internationization - which is the point of using ResourceBundles. See this related question and associated accepted answer. http://stackoverflow.com/questions/10229156/how-many-characters-can-utf-8-encode – Darrell Teague Aug 04 '16 at 19:26
3

This worked for me very well. And it doesn't reload the bundle everytime. I tried to take some stats to load and reload the bundle from external file location.

File file = new File("C:\\temp");
URL[] urls = {file.toURI().toURL()};
ClassLoader loader = new URLClassLoader(urls);
ResourceBundle rb = ResourceBundle.getBundle("myResource", Locale.getDefault(), loader);

where "c:\temp" is the external folder (NOT on the classpath) holding the property files, and "myResource" relates to myResource.properties, myResource_fr_FR.properties, etc.

Note: If you have the same bundle name on your classpath then it will be picked up by default using this constructor of URLClassLoader.

Credit to http://www.coderanch.com/t/432762/java/java/absolute-path-bundle-file

Find some of the stats below, all time in ms. I am not worried about the initial load time as that could be something with my workspace or code that I am trying to figure out but what I am trying to show is the reload took way lesser telling me its coming from memory.

Here some of the stats:

  • Initial Locale_1 load took 3486
  • Reload Locale_1 took 24
  • Reload Locale_1 took 23
  • Reload Locale_1 took 22
  • Reload Locale_1 took 15
  • Initial Locale_2 load took 870
  • Reload Locale_2 took 22
  • Reload Locale_2 took 18
  • Initial Locale_3 load took 2298
  • Reload Locale_3 took 8
  • Reload Locale_3 took 4
smn.tino
  • 2,272
  • 4
  • 32
  • 41
Prashant Rajput
  • 141
  • 1
  • 3
2

I would prefer to use the resourceboundle class to load the properties - just to get it done in one line instead of 5 lines code through stream, Properties class and load().

FYI ....

    public void init(ServletConfig servletConfig) throws ServletException {
    super.init(servletConfig);

    try {

            /*** Type1 */
        Properties props = new Properties();

        String fileName = getServletContext().getRealPath("WEB-INF/classes/com/test/my.properties");
    //          stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
    //          stream = ClassLoader.getSystemResourceAsStream("WEB-INF/class/com/test/my.properties");  

        InputStream stream = getServletContext().getResourceAsStream("/WEB-INF/classes/com/test/my.properties");

  //        props.load(new FileInputStream(fileName));
        props.load(stream);

        stream.close();
        Iterator keyIterator = props.keySet().iterator();
        while(keyIterator.hasNext()) {
                String key = (String) keyIterator.next();
                String value = (String) props.getProperty(key);
                System.out.println("key:" + key + " value: " + value);
        }

  /*** Type2:  */
  // Just get it done in one line by rb instead of 5 lines to load the properties
  // WEB-INF/classes/com/test/my.properties file            
  //            ResourceBundle rb = ResourceBundle.getBundle("com.test.my", Locale.ENGLISH, getClass().getClassLoader());
        ResourceBundle rb = ResourceBundle.getBundle("com.ibm.multitool.customerlogs.ui.nl.redirect");
        Enumeration<String> keys = rb.getKeys();
        while(keys.hasMoreElements()) {
            String key = keys.nextElement();
            System.out.println(key + " - " + rb.getObject(key));
        }
    } catch (IOException e) {
        e.printStackTrace();
        throw new ServletException("Error loading config.", e);
    } catch (Exception e) {
        e.printStackTrace();
        throw new ServletException("Error loading config.", e);
    }       

}
Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
Subba Reddy
  • 431
  • 5
  • 6
0

I think that you want the file's parent to be on the classpath, not the actual file itself.

Try this (may need some tweaking):

String path = "c:/temp/mybundle.txt";
java.io.File fl = new java.io.File(path);

try {
   resourceURL = fl.getParentFile().toURL();
} catch (MalformedURLException e) {
   e.printStackTrace();                     
}               

URLClassLoader urlLoader = new URLClassLoader(new java.net.URL[]{resourceURL});
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("mybundle.txt", 
                java.util.Locale.getDefault(), urlLoader );
0

If you wanted to load message files for different languages, just use the shared.loader= of catalina.properties... for more info, visit http://theswarmintelligence.blogspot.com/2012/08/use-resource-bundle-messages-files-out.html

JanaVish
  • 43
  • 5
0

This works for me:

File f = new File("some.properties");
Properties props = new Properties();
FileInputStream fis = null;
try {
    fis = new FileInputStream(f);
    props.load(fis);
} catch (FileNotFoundException e) {
    e.printStackTrace();                    
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();
            fis = null;
        } catch (IOException e2) {
            e2.printStackTrace();
        }
    }
}           
sius
  • 1
0
public class One {

    private static One one = null;

    Map<String, String> configParameter = Collections.synchronizedMap(new HashMap<String, String>());

    private One() {
        ResourceBundle rb = ResourceBundle.getBundle("System", Locale.getDefault());

        Enumeration en = rb.getKeys();
        while (en.hasMoreElements()) {
            String key = (String) en.nextElement();
            String value = rb.getString(key);
            configParameter.put(key, value);

        }
    }

    public static One getInstance() {
        if (one == null) {
            one= new One();
        }

        return one;

    }

    public Map<String, String> getParameter() {

        return configParameter;
    }



    public static void main(String[] args) {
        String string = One.getInstance().getParameter().get("subin");
        System.out.println(string);

    }
}
SUBZ
  • 139
  • 1
  • 7
0
ResourceBundle rb = ResourceBundle.getBundle("service"); //service.properties
System.out.println(rb.getString("server.dns")); //server.dns=http://....
josliber
  • 43,891
  • 12
  • 98
  • 133
0

The file name should have .properties extension and the base directory should be in classpath. Otherwise it can also be in a jar which is in classpath Relative to the directory in classpath the resource bundle can be specified with / or . separator. "." is preferred.