I'm trying to create a small application that will copy some .jar files into the latest jre.
Is there anyway of finding out which is this path?
I've looking at the File class and I've found several methods that will create an empty file, but I didn't find anything that would help me copying a file into a given path.
Am I missing any important class?
Thanks
To copy files you can use the java.nio.channels.FileChannel class from the nio library.
package.
For example:
// Create channel for the source
FileChannel srcChannel = new FileInputStream("srcFileLocation").getChannel();
// Create channel for the destination
FileChannel dstChannel = new FileOutputStream("dstFileLocation").getChannel();
// Copy file contents from source to destination
dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
// Close the channels
srcChannel.close();
dstChannel.close();
Firstly there isn't a helper method for copying a file until Java 7 (not yet released). Secondly it is inadvisable to try copying into the JRE directory because you may not have sufficient permission. To find the location of the JRE use System.getProperty("java.home")
To copy:
byte[] buffer = new byte[16384];
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
while (true) {
int n = in.read(buffer);
if (n == -1)
break;
out.write(buffer, 0, n);
}
in.close();
out.close();
Related
Is there a way in Java to construct a File instance on a resource retrieved from a jar through the classloader?
My application uses some files from the jar (default) or from a filesystem directory specified at runtime (user input). I'm looking for a consistent way of
a) loading these files as a stream
b) listing the files in the user-defined directory or the directory in the jar respectively
Edit: Apparently, the ideal approach would be to stay away from java.io.File altogether. Is there a way to load a directory from the classpath and list its contents (files/entities contained in it)?
I had the same problem and was able to use the following:
// Load the directory as a resource
URL dir_url = ClassLoader.getSystemResource(dir_path);
// Turn the resource into a File object
File dir = new File(dir_url.toURI());
// List the directory
String files = dir.list()
ClassLoader.getResourceAsStream and Class.getResourceAsStream are definitely the way to go for loading the resource data. However, I don't believe there's any way of "listing" the contents of an element of the classpath.
In some cases this may be simply impossible - for instance, a ClassLoader could generate data on the fly, based on what resource name it's asked for. If you look at the ClassLoader API (which is basically what the classpath mechanism works through) you'll see there isn't anything to do what you want.
If you know you've actually got a jar file, you could load that with ZipInputStream to find out what's available. It will mean you'll have different code for directories and jar files though.
One alternative, if the files are created separately first, is to include a sort of manifest file containing the list of available resources. Bundle that in the jar file or include it in the file system as a file, and load it before offering the user a choice of resources.
Here is a bit of code from one of my applications...
Let me know if it suits your needs.
You can use this if you know the file you want to use.
URL defaultImage = ClassA.class.getResource("/packageA/subPackage/image-name.png");
File imageFile = new File(defaultImage.toURI());
A reliable way to construct a File instance on a resource retrieved from a jar is it to copy the resource as a stream into a temporary File (the temp file will be deleted when the JVM exits):
public static File getResourceAsFile(String resourcePath) {
try {
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
if (in == null) {
return null;
}
File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
tempFile.deleteOnExit();
try (FileOutputStream out = new FileOutputStream(tempFile)) {
//copy stream
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
return tempFile;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Try this:
ClassLoader.getResourceAsStream ("some/pkg/resource.properties");
There are more methods available, e.g. see here:
http://www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html
This is one option: http://www.uofr.net/~greg/java/get-resource-listing.html
I am working in Java platform. I need to copy a file from the package to some folders in desktop. I am using input stream and output stream classes to do it, it is doing the job pretty well inside NetBeans.
The problem is, it's not copying the file while I am running the JAR file to test the application, and it is saying NULL.
File source = new File("src/jrepo/css/bs.css");
File dest = new File(ResultPath + "/css/bs.css");
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(source);
os = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
} finally {
is.close();
os.close();
}
Your problem is with
new File("src/jrepo/css/bs.css");
The constructor for File(String) takes a full path to the file. You are using a relative path. If you are trying to read the file from the operating system, use the full path. If you are reading it from the jar file, then use this approach instead.
I found the way since I am using JavaFX, there is a problem which stops the file copying of CSS files. In order to resolve that issue just change the run time settings of the project in Netbeans. Right click the title of the project→go to Properties→Build→Packaging→uncheck the Binary Encode JavaFX CSS files checkbox and then save the project and rebuild it.
I am making a 1 file program in java, and I have a .chm file that I want to be called when the user asks how to use the program. I don't want to have the file outside the .jar file.
Maybe what I'm asking is impossible, the only thing I know about compiling is that if I hit "clean and build" button it generates a .jar file out of my .java files. Is there a way to do this?
PS: I use NetBeans to create java programs.
You can include any file inside a jar (it is a zip file). Then you have to use getResource() to get an access to the embedded file in your jar. That would return an URL that you can use to get an InputStream by calling openStream() and read from it, possibly extracting it to the hard drive for display, etc.
The use is to put such files in a "resource" or "res" folder, inside the "src" directory. Here is how it looks in my Eclipse:
Then I access my images by:
URL uImg = getClass().getResource("/res/16/Actions-edit-delete-icon-16.png");
InputStream is = uImg.openStream();
// Read the content from 'is' e.g. to extract it somewhere
is.close();
EDIT: As an example, to extract your file "TJ.chm" from "res" directory of your jar into a file "/tmp/TJ.chm" you would do like:
// Add all necessary try/catch
InputStream is = ucmh.openStream();
OutputStream os = new BufferedOutputStream(new FileOutputStream("/tmp/TJ.chm"));
int len = 0;
byte[] buffer = new byte[8192]; // Or whichever size you prefer
while ((len = is.read(buffer)) > -1)
os.write(buffer, 0, len);
os.close();
is.close();
Im trying to copy a file in java and move it to a new folder. This is the code i HAve been using but I always get this error "(Access is denied) in the specified directory". Is there a way i can fix this or a better way to copy the files? thanks
try{
File f1 = new File(fpath);
File f2 = new File("C:/users/peter/documents/foldertest2/hats");
InputStream in = new FileInputStream(f1);
//For Append the file.
//OutputStream out = new FileOutputStream(f2,true);
//For Overwrite the file.
OutputStream out = new FileOutputStream(f2);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0){
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("File copied.");
}
catch(FileNotFoundException ex){
System.out.println(ex.getMessage() + " in the specified directory.");
System.exit(0);
}
catch(IOException e){
System.out.println(e.getMessage());
}
UPDATE:
I checked the folder permissions and they are all open for all users and mine
Apache Commons IO is also another way to go, specifically FileUtils.copyFile(); it handles all the heavy lifting for you.
Use Java 7:
import static java.nio.file.StandardCopyOption.*;
Files.copy(source, target, REPLACE_EXISTING);
http://docs.oracle.com/javase/tutorial/essential/io/copy.html
Is there a way i can fix this or a better way to copy the files?
If you have the option, I would recommend you to go with Java version 7, and use the Path.copyTo method.
Copy the file located by this path to a target location. [...]
Otherwise I would recommend at least using the NIO packages and FileChannels.
Edit ups messed up, second try:
You have to give the FileOutputStream a valid file name, just append the name of your file to the target path C:/users/peter/documents/foldertest2/hats/hat3 with only the folder name it will try to access the folder as if it was a file and fail.
If you get this exception the access is really denied, i.e. you just do not have rights to write to the specified directory or file.
So, first check it. Try for example to create the file in specified directory manually. Do you probably try to create file in somebody else' home directory? Or your java program is running as other user? What about foldertest2? Does it exist and writable? Try to copy your file there.
And the final tip. When you manage to copy the file, I'd recommend you to use IOUtils.copy() (from jacarta commons). I use it a lot. It does almost exactly what you implemented but have to write of code one line only.
Hmm it looks like you are trying to run this on windows, should you not be using \ in your path instead of / ?
As AlexR said check your permissions on the directory you are trying to write to.
I've got a WAR file that I need to add two files to. Currently, I'm doing this:
File war = new File(DIRECTORY, "server.war");
JarOutputStream zos = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(war)));
//Add file 1
File file = new File(DIRECTORY, "file1.jar");
InputStream is = new BufferedInputStream(new FileInputStream(file));
ZipEntry e = new ZipEntry("file1.jar");
zos.putNextEntry(e);
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf, 0, buf.length)) != -1) {
zos.write(buf, 0, len);
}
is.close();
zos.closeEntry();
//repeat for file 2
zos.close();
The result is that the previous contents get clobbered: the WAR has only the 2 files I just added in it. Is there some sort of append mode that I'm not using or what?
Yeah, there's an extra boolean argument to the FileOutputStream constructor which lets you force it to append to the file rather than overwrite it. Change your code to
JarOutputStream zos = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(war, True)));
and it should work the way you want.
It seems this can't be done. I thought it was for a while, but it seems that it wasn't quite having the effect I wanted. Doing it this way resulted in the equivalent of two separate jar files concatinated together. The weird part was that the tools were making some sense of it. JAR found the first, original jar file and read me that. Glassfish's classloader was finding the later, new part, resulting in it loading only the added files as if they were all of the app. Weird.
So I've resurted to creating a new war, adding the contents of the old, adding the new files, closing, and copying the new over the old.
I have the same problem; I'm looking for an easy way to update a file in an existing jar file. If it's so easy to do a "jar uf foo.jar ..." command, how come there isn't a way to use Java API's to do the same?
Anyway, here is the RFE to add this functionality to Java; it also suggests some work-arounds:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4129445
And here is a library that purports to make this a lot easier, by treating JARs/ZIPs like virtual directories:
https:// truezip.dev.java.net
I haven't figured out yet which approach I'm going to use for my current problem.