34

Java7 ships with a default Path implementation for local files. Is there a Path implementation for URLs?

For example, I should be able to copy a remote resource using the following code:

Path remote = Paths.get(new URI("http://www.example.com/foo/bar.html"));
Path local = Paths.get(new URI("/bar.html"));
Files.copy(remote, local);

Currently, this throws java.nio.file.FileSystemNotFoundException: Provider "http" not installed. I could probably implement this myself but I'd rather not reinvent the wheel.

Gili
  • 86,244
  • 97
  • 390
  • 689
  • What's against Files.copy(InputStream, Path)? Do URL's constitute a path into the world that is the web? Or are they more like pointer? What are you likely to gain? – Maarten Bodewes Jan 09 '12 at 03:27
  • @owlstead, My library needs to return opaque Paths to users. They can copy these (read-only) Paths to the local filesystem without needing to know or care whether the file resides locally (i.e. in a database) or remotely (web server). InputStreams are missing attributes I'd like to provide my users, such as the filename or the lastModified timestamp. – Gili Jan 09 '12 at 04:06
  • Understood, but what the users see dont necessarily have to be reflected by the underlying implementation. – Maarten Bodewes Jan 09 '12 at 04:09
  • @owlstead, I don't understand. What do you mean? – Gili Jan 09 '12 at 04:16
  • Although the users may see it as a path, you don't necessarily have to use the new FileSystem architecture to implement it. Things like directory listings, are probably not enabled anyway. That doesn't say you cannot, but implementing it may not be worth it. – Maarten Bodewes Jan 09 '12 at 08:49

3 Answers3

2

You can do:

URI uri = new URI("http://www.example.com/foo/bar.html");
try (InputStream is = uri.toURL().openStream()) {
    // ...
}

It will work for http, https and file out of the box, probably for few more.

For relative URIs, you have to resolve them first:

URI relative = new URI("bar.html");
URI base = new URI("http://www.example.com/foo/");
URI absolute = base.resolve(relative);
System.out.println(absolute); // prints "http://www.example.com/foo/bar.html"

Now you can call toURL().openStream() on the absolute URI.

Oliv
  • 10,221
  • 3
  • 55
  • 76
2

It seems like what you're really trying to do is accomplish what FTP does - copy files from one place to another. I would suggest you find better ways to do this with existing FTP code libraries.

URIs are not file system paths, so you can't treat them as such. They are addresses/resource locators that, when you go there with your browser (or another client that handles them), they trigger some action as defined by the server that's behind them. There's no standard for what that server does, hence the flexibility of web services. Therefore, if your server is doing to accept HTTP requests in this manner to facilitate file copies, you're going to have to roll your own, and pass the file data into a POST request.

To say it another way, (1) don't treat URIs like they are file system paths - they aren't, (2) find an FTP library to copy files, and/or (3) if you really want to build a web service that does this, abstract the details of the file copying via a POST request. If you do #3 understand that what your building is pretty close to custom, and that it will probably only work on a subset of sites that follow your particular design (i.e. the ones you build yourself). There's no standard set of parameters or "file copying" via POST command that I'm aware of that you can leverage to make this "just work" - you're going to have to match up your HTTP request with the web service on the server side.

Michael-O
  • 18,123
  • 6
  • 55
  • 121
jefflunt
  • 33,527
  • 7
  • 88
  • 126
  • For what it's worth, someone has rolled a generic HTTP directory browser at https://issues.apache.org/jira/browse/VFS-199. In my case, the web server is required to follow a directory structure I specify so I'm going to need to roll a corresponding Path implementation. Thanks for helping me understand why a custom implementation is needed. – Gili Jan 09 '12 at 04:14
  • Coolio - glad I could help, and glad you found that project. – jefflunt Jan 09 '12 at 04:17
  • 1
    @normalocity It's almost unrelated and I'm just shooting this off of the top of my brain, but I think there isn't a method in Java 7 currently that would return a `Path` for a _classpath resource_, which would be very nice. What do you think about that? I think it would be nice, because a `Path` is much nicer than a `URL`. – Kohányi Róbert Jan 09 '12 at 06:32
  • @KohányiRóbert, that's actually an excellent idea! I encourage you to build it and send us the link. Seriously. – Gili Jan 12 '12 at 19:04
  • Hm, I suppose so. I generally write apps with all my resources under the path of the app, so I can consistently rely upon relative paths. However, I know plenty of people write apps that purposely go beyond their own local directory, it would probably be useful for them. – jefflunt Jan 13 '12 at 00:06
0

I had to deal with a similar problem and wrote a little method to solve this, you can find below.

It works fine for concatenation of URL and relative suffixes. Be careful not to give suffix absolute because of the behaviour of URI resolve function.

private URI resolveURI(String root, String suffix) {
    URI uri;
    try {
        uri = new URI(root + "/").resolve(suffix);
    } catch (URISyntaxException e) {
        //log
    }
    return uri;
}
sanver
  • 114
  • 2