简体   繁体   中英

Update a file inside a JAR in a specific directory with jar command

So I've been looking high and low for an answer to this and obviously haven't found a satisfactory answer.

The problem is that I want to update a JAR (or any file for that matter) inside a JAR, but said file is inside a folder structure, which I would like to avoid reproducing outside the JAR just so I can update it.

Example:

Foo.jar (root directory)
/
|->/folder1
|
|->/folder2
|
|->/foo
    |
    |-->/bar
         |
         |---->/baz
               |
               |------>file_to_update.jar

So, if I want to update this using the jar command, I would have to first create the same folder structure outside the JAR and then do

jar -uf Foo.jar -C foo/bar/baz/file_to_update.jar

However I would like to avoid creating this folder structure since for certain files it can be quite deep and also because I might need to update selected files all over the container JAR, so I would not like to create so many folders with a specific structure just so the jar command can update them.

To put it in another way, I would like to tell the jar command to update a specific destination file inside a specific destination directory, using a specific source file inside a specific source directory.

Ie something like

jar -uf Foo.jar -sourceFile /x/y/z/filetoupdate -destFile /a/b/c/filetoupdate 

(I know this syntax doesn't work, it's just to exemplify what I need).

Can this be done? It would strike me as very odd that I would absolutely need to mimic the whole folder structure when the jar command could find a match for it or something, since I could have the need to update a file inside a folder structure that is 100 folders deep. That would be overly complex to reproduce just to update the file.

Also, I know a regular ZIP utility could be used, but the one I have available in Linux is not updating the file even if it says it did (upon re-opening the jar, it has the old version intact), and right now I can't go looking for another one (company policy, no time, testing issues, you name it).

Finally, if I can do this from a command line, it means I can create a batch file to update lots of specific files without having to create the folder structure.

I forgot to say that I would also like to avoid having to unjar, update, rejar the whole thing, as this JAR can go upwards to 2GB so it takes a while to do this just to, basically, add a little resource file to my gigantic JAR.

Any help on this is greatly appreciated!

As the accepted answer already pointed out, you can't use neither the zip nor the jar command to insert a specific file on the file system to a specific directory inside the compressed file.

But there is this workaround , which in a nutshell extracts a specific file inside the compressed file first, you can update it and then put it back into the compressed file:

1. Extracting a single file :
Consider a jar with the following contents

$ jar tvf foo.jar 
 0 Thu Jan 10 00:05:06 IST 2013 META-INF/
68 Thu Jan 10 00:05:06 IST 2013 META-INF/MANIFEST.MF
 0 Thu Jan 10 00:04:30 IST 2013 x/
 0 Thu Jan 10 00:07:36 IST 2013 x/b/
 9 Thu Jan 10 00:07:36 IST 2013 x/b/hello.txt
 0 Thu Jan 10 00:04:30 IST 2013 x/a/

To extract only hello.txt, you have to give fully qualified path of the file-to-extract. Jar creates appropriate folders too.

Example :

$ jar xvf foo.jar x/b/hello.txt
inflated: x/b/hello.txt

$ tree x/
x
└── b
    └── hello.txt  
1 directory, 1 file

2. Updating a Single File

  1. Modify the extracted file
  2. update the jar using the 'u' flag. Provide the exploded directory root and jar shall update all the path elements under it.

Example:

$ jar vfu foo.jar x/
adding: x/(in = 0) (out= 0)(stored 0%)
adding: x/b/(in = 0) (out= 0)(stored 0%)
adding: x/b/hello.txt(in = 23) (out= 11)(deflated 52%)

3. Which version of jar I tried this out with ?

I used jar bundled with JDK 7 on Fedora 17.


I have verified all the steps mentioned here. Hope this helps.

4129445 : An API to incrementally update ZIP files in the Sun/Oracle bug database asks for this feature to be implemented in the java api.

From the Evaluation:

"It is easy to sympathize with those who want this bug fixed. It is perhaps easier to sympathize with those who have, inadvertently, overwritten JAR files that are already in-use by a running JVM."

and

"It would have been nice if the jar & zip APIs had allowed for mutable zip files from day one. But at this point adding mutability to jar & zip files from Java(or rather, increasing the ease of mutating them) seems likely to introduce more hard-to-debug problems."

This previous discussion shows some Java source code for updating a zip (or jar) file.

It's not entirely clear to me whether this will actually be any faster than using jar -u , but at least you should be able to adapt that code so that you don't have to recreate the file structure on disk.

Edit: Here is the documentation on the 'jar' utility - you can see for yourself that the particular behavior that you're looking for, while it would be useful, isn't there.

I think that the reason is that the command-line interface is basically a clone of the Unix/Linux 'tar' command. Of course, it produces zip format, rather than tar.

Edit #2 - It occurred to me that to add a file to a zip, you'd just have to strip off the central directory from the end of the file, append the new entry, and then re-write the central directory. An update would be the same thing, except instead of adding the entry to the directory, you'd update the existing directory entry to point to the new zip entry.

While exploring this possibility, I found that Java 7 includes a zip file system provider which looks like it does this, and could form the basis of a solution for what you want to do.

I think this is due to how the classes in the java.util.zip package work. They sit on top of streams.

The ZipFile class is built on top of a ZipFileInputStream. Writing zipfiles is done by feeding the ZipEntries one by one to a ZipOutputStream.

I assume the jar executable is built on top of these classes.

I too was trying to update a jar without reproducing the jar's file structure external to the jar, and for some reason the jar uf jarFileName -C ... command never let me copy the file to a child directory in the jar. I then tried cutting and pasting the file into the jar using ubuntu 14.04's built in archive manager (ie right click on jar file and chose "open with archive manager" then paste the file anywhere in the jar's file structure), and it worked. It's not a cli solution but it works. Hope this saves someone else some time.

It works , but its not the extact solution you are looking at.

Instead of manually creating folder structure , i am asking to mention the whole path ,so mkdir will create folder and sub-directories too.hope this helps....

set /p Folder=where you want to move inside jar 
set /p File=Mention path of file to be moved 
set /p Jarfile=Where is your jar file
mkdir %Folder%
copy %File% %Folder%
jar -uvf %Jarfile% %File%
rd /s /q %Folder%
rmdir %Folder%

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM