2

This is what I'm trying to do:

public String load(String path) {
  //...
}
load("file:/tmp/foo.txt"); // loads by absolute file name
load("classpath:bar.txt"); // loads from classpath

I think it's possible to do with JDK, but can't find out how exactly.

yegor256
  • 102,010
  • 123
  • 446
  • 597

2 Answers2

3

I can think of two approaches:

  • Just write plain Java code to extract the "scheme" from those URI-like strings, and then dispatch to the different code to load the file in different ways.

  • Register a custom URL stream handler to deal with the "classpath" case and then use URL.openStream() to open the stream to read the object.

The package documentation for java.net has some information about how stream handlers are discovered.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
-1

From my libraries omino roundabout, the two methods you'll need... I need them everywhere. The resource reader is relative to a class, at least to know which jar to read. But the path can start with / to force it back to the top. Enjoy!

(You'll have to make our own top level wrapper to look for "file:" and "classpath:".)

see also http://code.google.com/p/omino-roundabout/

    public static String readFile(String filePath)
{
    File f = new File(filePath);
    if (!f.exists())
        return null;

    String result = "";
    try
    {
        FileReader in = new FileReader(f);
        boolean doing = true;
        char[] bunch = new char[10000];
        int soFar = 0;
        while (doing)
        {
            int got = in.read(bunch, 0, bunch.length);
            if (got <= 0)
                doing = false;
            else
            {
                String k = new String(bunch, 0, got);
                result += k;
                soFar += got;
            }
        }
    } catch (Exception e)
    {
        return null;
    }

    // Strip off the UTF-8 front, if present. We hate this. EF BB BF
    // see http://stackoverflow.com/questions/4897876/reading-utf-8-bom-marker for example.
    // Mysteriously, when I read those 3 chars, they come in as 212,170,248. Fine, empirically, I'll strip that, too.

    if(result != null && result.length() >= 3)
    {
        int c0 = result.charAt(0);
        int c1 = result.charAt(1);
        int c2 = result.charAt(2);
        boolean leadingBom = (c0 == 0xEF && c1 == 0xBB && c2 == 0xBF);
        leadingBom |= (c0 == 212 && c1 == 170 && c2 == 248);

        if(leadingBom)
            result = result.substring(3);
    }

    // And because I'm a dictator, fix up the line feeds.
    result = result.replaceAll("\\r\\n", "\n");
    result = result.replaceAll("\\r","\n");
    return result;
}

static public String readResource(Class<?> aClass,String srcResourcePath)
{
    if(aClass == null || srcResourcePath==null || srcResourcePath.length() == 0)
        return null;

    StringBuffer resultB = new StringBuffer();
    URL resourceURL = null;
    try
    {
        resourceURL = aClass.getResource(srcResourcePath);
    }
    catch(Exception e) { /* leave result null */ }

    if(resourceURL == null)
        return null; // sorry.

    try
    {
        InputStream is = resourceURL.openStream();
        final int BLOCKSIZE = 13007;
        byte[] bytes = new byte[BLOCKSIZE];

        int bytesRead = 0;
        while(bytesRead >= 0)
        {
            bytesRead = is.read(bytes);
            if(bytesRead > 0)
            {
                char[] chars = new char[bytesRead];
                for(int i = 0; i < bytesRead; i++)
                    chars[i] = (char)bytes[i];
                resultB.append(chars);
            }
        }
    }
    catch(IOException e)
    {
        return null; // sorry
    }

    String result = resultB.toString();
    return result;
}

(edit -- removed a stray reference to OmString, to keep it standalone here.)

david van brink
  • 3,604
  • 1
  • 22
  • 17
  • It is rarely a good idea to use `FileReader`, or anything that uses the default character encoding. Your comment about bizarre behavior with Unicode BOMs should be a hint that you aren't handling encodings properly. Also, why do these two fairly long methods have names that sound like they do similar thing yet share no common logic? You may want to consider having them both create an `InputStream` which they then pass to a common private helper method. – Laurence Gonsalves Aug 20 '11 at 04:33
  • Hi @Laurence -- thanks for looking, & your comments are well-taken & appreciated. Thanks for the encoding pointer. Your note about shared inner helper method makes sense. Why are they like this now? They were written at far different times, get heavy use, and, well, until a test fails, it's off my radar. – david van brink Aug 20 '11 at 05:18