I'm using Spring's Resource abstraction to work with resources (files) in the filesystem. One of the resources is a file inside a JAR file. According to the following code, it appears the reference is valid
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
// The path to the resource from the root of the JAR file
Resource fileInJar = resourcePatternResolver.getResources("/META-INF/foo/file.txt");
templateResource.exists(); // returns true
templateResource.isReadable(); // returns true
At this point, all is well, but then when I try to convert the Resource to a File
templateResource.getFile();
I get the exception
java.io.FileNotFoundException: class path resource [META-INF/foo/file.txt] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/D:/m2repo/uic-3.2.6-0.jar!/META-INF/foo/file.txt
at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:198)
at org.springframework.core.io.ClassPathResource.getFile(ClassPathResource.java:174)
What is the correct way to get a File reference to a Resource that exists inside a JAR file?
What is the correct way to get a File
reference to a Resource that exists
inside a JAR file?
The correct way is not doing that at all because it's impossible. A File represents an actual file on a file system, which a JAR entry is not, unless you have a special file system for that.
If you just need the data, use getInputStream(). If you have to satisfy an API that demands a File object, then I'm afraid the only thing you can do is to create a temp file and copy the data from the input stream to it.
If you want to read it, just call resource.getInputStream()
The exception message is pretty clear - the file does not reside on the file-system, so you can't have a File instance. Besides - what will do do with that File, apart from reading its content?
A quick look at the link you provided for Resource documentation, says the following:
Throws: IOException if the resource cannot be resolved as absolute file path,
i.e. if the resource is not available in a file system
Maybe the text file is inside a jar? In that case you will have to use getInputStream() to read its contents.
Just adding an example to the answers here. If you need a File (and not just the contents of it) from within your JAR, you need to create a temporary file from the resource first. (The below is written in Groovy):
InputStream inputStream = resourceLoader.getResource('/META-INF/foo/file.txt').inputStream
File tempFile = new File('file.txt')
OutputStream outputStream = new FileOutputStream(tempFile)
try {
IOUtils.copy(inputStream, outputStream)
} catch (IOException e) {
// Handle exception
} finally {
outputStream.close()
}
Related
I am trying to copy a file from an InputStream into a local directory. I created a local directory called test, and it is located in my package root.
public void copyFileFromInputStream(InputStream is) {
Path to = Paths.get("test");
Files.copy(is, to);
}
Clearly I am misunderstanding Files.copy(...), because it seems like it is trying to create a new file called "test" instead of placing the file into the directory "test".
How do I write the file into the directory?
First create the new directory, then copy the stream to a new file in that directory:
Path to = Paths.get("mynewdir/test");
Files.copy(is, to);
Also bare in mind that your InputStream does not have a filename, so you will always need to provide a filename when writing the stream to disk. In your example, it will indeed try to create a file 'test', but apparently that is a folder that already exists (hence the Exception). So you need to specify the full filename.
Here is a answer for you question:
Referring to you code snippet: Paths.get("test");
you're asking a file path to the file named "test" in the current directory but not the directory.
If you want to refer the file under test directory which in tern under your current directory. use the following:
Paths.get("test/filename.ext") to which you want to write your stream data.
If you run your app twice, you get "FileAlreadyExistsException" because copy method on Files writes to new file , if exists it'll not override it.
I hope this helps you!
The 'to' parameter of Files.copy(from, to) is the path to the destination file.
Try specifying what file name inside the test directory:
Path to = Paths.get("test/newfilename");
Files.copy(is, to);
You can use the option StandardCopyOption.REPLACE_EXISTING :
public void copyFileFromInputStream(InputStream is) {
Path to = Paths.get("test");
Files.copy(is, to, StandardCopyOption.REPLACE_EXISTING);
}
My app needs to get an existing file for processing. Now I have the path of the file in String format, how can I get the File with it? Is it correct to do this:
File fileToSave = new File(dirOfTheFile);
Here dirOfTheFile is the path of the file. If I implement it in this way, will I get the existing file or the system will create another file for me?
That's what you want to do. If the file exists you'll get it. Otherwise you'll create it. You can check whether the file exists by calling fileToSave.exists() on it and act appropriately if it does not.
The new keyword is creating a File object in code, not necessarily a new file on the device.
I would caution you to not use hardcoded paths if you are for dirOfFile. For example, if you're accessing external storage, call Environment.getExternalStorageDirectory() instead of hardcoding /sdcard.
The File object is just a reference to a file (a wrapper around the path of the file); creating a new File object does not actually create or read the file; to do that, use FileInputStream to read, FileOutputStream to write, or the various File helper methods (like exists(), createNewFile(), etc.) for example to actually perform operations on the path in question. Note that, as others have pointed out, you should use one of the utilities provided by the system to locate directories on the internal or external storage, depending on where you want your files.
try this..
File fileToSave = new File(dirOfTheFile);
if(fileToSave.exists())
{
// the file exists. use it
} else {
// create file here
}
if parent folder is not there you may have to call fileToSave.getParentFile().mkdirs() to create parent folders
i know this question has been asked several times, but i think my problem differs a bit from the others:
String resourcePath = "/Path/To/Resource.jar";
File newFile = new File(resourcePath);
InputStream in1 = this.getClass().getResourceAsStream(resourcePath);
InputStream in2 = this.getClass().getClassLoader().getResourceAsStream(resourcePath);
The File-Object newFile is completely fine (the .jar file has been found and you can get its meta-data like newFile.length() etc)
On the other hand the InputStream always return null.
I know the javadoc says that the getResourceAsStream() is null if there is no resource found with this name, but the File is there! (obviously, because it's in the File-Object)
Anyone know why this happens and how i can fix it so that i can get the .jar File in the InputStream?
The getResourceAsStream() method doesn't load a file from the file system; it loads a resource from the classpath. You can use it to load, for example, a property file that's packaged inside your JAR. You cannot use it to load a file from the file system.
So, if your file resides on the file system, rather than in your JAR file, better use the FileInputStream class.
In my Maven project, I have a xls file in src/main/resources.
When I read it like this:
InputStream in = new
FileInputStream("src/main/resources/WBU_template.xls");
everything is ok.
However I want to read it as InputStream with getResourceAsStream. When I do this, with or without the slash I always get a NPE.
private static final String TEMPLATEFILE = "/WBU_template.xls";
InputStream in = this.getClass.getResourceAsStream(TEMPLATEFILE);
No matter if the slash is there or not, or if I make use of the getClassLoader() method, I still get a NullPointer.
I also have tried this :
URL u = this.getClass().getResource(TEMPLATEFILE);
System.out.println(u.getPath());
the console says.../target/classes/WBU_template.xls
and then get my NullPointer.
What am I doing wrong ?
FileInputStream will load a the file path you pass to the constructor as relative from the working directory of the Java process.
getResourceAsStream() will load a file path relative from your application's classpath.
When you use .getClass().getResource(fileName) it considers the location of the fileName is the same location of the of the calling class.
When you use .getClass().getClassLoader().getResource(fileName)
it considers the location of the fileName is the root - in other words bin folder.
The file should be located in src/main/resources when loading using Class loader
In short, you have to use .getClass().getClassLoader().getResource(fileName) to load the file in your case.
I usually load files from WEB-INF like this
session.getServletContext().getResourceAsStream("/WEB-INF/WBU_template.xls")
Does the following statement:
new File(filename);
associate a process file descriptor with the File object? Tried to search the same but without any success.
Ideally, it should not statically associate the file descriptor with the File object. Whenever, function calls are executed a file descriptor should get associated with the File Object for the period of time when the function call gets executed.
Any help appreciated.
There's no file descriptor, because new File(filename) does not open the file. It's just a easily manipulable representation of a path name.
File descriptors refer to open files. The fact that the file is not opened is not explicitly documented, but it follows from the principle of least surprise and from the fact that no exceptions are listed corresponding to failure to open the file.
No, new File(...) only is an object representing the filename, without even checking that there exists a file (or directory) with this name and/or path.
No. You can see this by examining the source of the File class yourself, from jdk 1.6.0_22:
public File(String pathname) {
if (pathname == null) {
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
Since you can call the File constructor with a path that doesn't yet exist, and since File objects can represent non-existent Files, it wouldn't be possible to associate descriptors with it.