How do I update a pre-existing Jar file - java

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.

Related

File is not getting copied in Java using input and output stream reader

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.

How to read a file created at runtime?

Using Java 8.
Basically, in a unit test (junit) I have this code:
callSomeCode();
assertTrue(new File(this.getClass().getResource("/img/dest/someImage.gif").getFile()).exists());
In callSomeCode(), I have this:
InputStream is = bodyPart.getInputStream();
File f = new File("src/test/resources/img/dest/" + bodyPart.getFileName()); //filename being someImage.gif
FileOutputStream fos = new FileOutputStream(f);
byte[] buf = new byte[40096];
int bytesRead;
while ((bytesRead = is.read(buf)) != -1)
fos.write(buf, 0, bytesRead);
fos.close();
The first time the test runs, this.getClass().getResource("/img/dest/someImage.gif")returns null although the file is well created.
The second time (when the file was already created during the first test run then just overwritten), it is non-null and the test passes.
How to make it work the first time?
Should I configure a special setup in IntelliJ to automatically refresh the folder where the file is created?
Note that I have this basic maven structure:
--src
----test
------resources
As the comment by nakano531 points out - your problem is not with the file system, but with the classpath. You're trying to read your file using a classloader by invoking the getClass().getResource(...) methods rather than reading the file using classes that access the file system directly.
For example, if you had written your test like this:
callSomeCode();
File file = new File("src/test/resources/img/dest/someImage.gif");
assertTrue(file.exists());
You wouldn't have had the issue you're having now.
Your other option is to implement the solution from the link that nakano531 provided: https://stackoverflow.com/a/1011126/1587791
i was stuck in the same situation, a way out is to delay the execution of line where it reads from the file which is created during run time. use this:
callSomeCode();
Thread.sleep(6000);
assertTrue(new File(this.getClass().getResource("/img/dest/someImage.gif").getFile()).exists());

Compile Java file with external files inside. (chm)

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();

How to create a java.io.File from a ByteArrayOutputStream?

I'm reading a bunch of files from an FTP. Then I need to unzip those files and write them to a fileshare.
I don't want to write the files first and then read them back and unzip them. I want to do it all in one go. Is that possible?
This is my code
FTPClient fileclient = new FTPClient();
..
ByteArrayOutputStream out = new ByteArrayOutputStream();
fileclient.retrieveFile(filename, out);
??????? //How do I get my out-stream into a File-object?
File file = new File(?);
ZipFile zipFile = new ZipFile(file,ZipFile.OPEN_READ);
Any ideas?
You should use a ZipInputStream wrapped around the InputStream returned from FTPClient's retrieveFileStream(String remote).
You don't need to create the File object.
If you want to save the file you should pipe the stream directly into a ZipOutputStream
ByteArrayOutputStream out = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(out);
// do whatever with your zip file
If, instead, you want to open the just retrieved file work with the ZipInputStream:
new ZipInputStream(fileClient.retrieveFileStream(String remote));
Just read the doc here and here
I think you want:
ZipInputStream zis = new ZipInputStream( new ByteArrayInputStream( out.toByteArray() ) );
Then read your data from the ZipInputStream.
As others have pointed out, for what you are trying to do, you don't need to write the downloaded ZIP "file" to the file system at all.
Having said that, I'd like to point out a misconception in your question, that is also reflected in some of the answers.
In Java, a File object does no really represent a file at all. Rather, it represents a file name or *path". While this name or path often corresponds to an actual file, this doesn't need to be the case.
This may sound a bit like hair-splitting, but consider this scenario:
File dir = new File("/tmp/foo");
boolean isDirectory = dir.isDirectory();
if (isDirectory) {
// spend a long time computing some result
...
// create an output file in 'dir' containing the result
}
Now if instances of the File class represented objects in the file system, then you'd expect the code that creates the output file to succeed (modulo permissions). But in fact, the create could fail because, something deleted the "/tmp/foo", or replaced it with a regular file.
It must be said that some of the methods on the File class do seem to assume that the File object does correspond to a real filesystem entity. Examples are the methods for getting a file's size or timestamps, or for listing the names in a directory. However, in each case, the method is specified to throw an exception if the actual file does not exist or has the wrong type for the operation requested.
Well, you could just create a FileOutputStream and then write the data from that:
FileOutputStream fos = new FileOutputStream(filename);
try {
out.writeTo(fos);
} finally {
fos.close();
}
Then just create the File object:
File file = new File(filename);
You need to understand that a File object doesn't represent any real data on disk - it's just a filename, effectively. The file doesn't even have to exist. If you want to actually write data, that's what FileOutputStream is for.
EDIT: I've just spotted that you didn't want to write the data out first - but that's what you've got to do, if you're going to pass the file to something that expects a genuine file with data in.
If you don't want to do that, you'll have to use a different API which doesn't expect a file to exist... as per Qwerky's answer.
Just change the ByteArrayOutputStream to a FileOutputStream.

Java, copying file to jre

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();

Categories

Resources