I am trying to make a program that will get all files within a jar file, and then copy them.
This is the code I am using to copying files:
public static void copyFolder(File src, File dest)
throws IOException{
if(src.isDirectory()){
//if directory not exists, create it
if(!dest.exists()){
dest.mkdir();
System.out.println("Directory copied from "
+ src + " to " + dest);
}
//list all the directory contents
String files[] = src.list();
for (String file : files) {
//construct the src and dest file structure
File srcFile = new File(src, file);
File destFile = new File(dest, file);
//recursive copy
copyFolder(srcFile,destFile);
}
}else{
//if file, then copy it
//Use bytes stream to support all file types
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
//copy the file content in bytes
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
in.close();
out.close();
System.out.println("File copied from " + src + " to " + dest);
}
}
But there is an error - java.io.FileNotFoundException: (Access is denied) in OutputStream out = new FileOutputStream(dest);. Now, I have no idea why or what does that really mean? How can I fix it?
Plus, I have absolutely no idea how to extract files from a jar file. I have seen the ZipFile class but I don't really know how to use it... So that leaves me with 3 questions:
1. Whats wrong with the copying code?
2. What does Access is denied mean?
3. Can anyone give me a method for getting files from a jar file? Because jar.listFiles() returns an empty list.
Thanks in advance!
Can anyone give me a method for getting files from a jar file?
I've written some utility classes to work with JARs/ ZIPs based on the NIO.2 File API (the library is Open Source):
Maven:
<dependency>
<groupId>org.softsmithy.lib</groupId>
<artifactId>softsmithy-lib-core</artifactId>
<version>0.4</version>
</dependency>
Tutorial:
http://softsmithy.sourceforge.net/lib/current/docs/tutorial/nio-file/index.html#ExtractJarResourceSample
Related
I am trying to copy files, folders, sub folders, zip files etc from a given location to another location. I used the code below.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class CopyDirectoryExample
{
public static void main(String[] args)
{
File srcFolder = new File("C:\\Users\\Yohan\\Documents");
File destFolder = new File("D:\\Test");
//make sure source exists
if(!srcFolder.exists()){
System.out.println("Directory does not exist.");
//just exit
System.exit(0);
}else{
try{
copyFolder(srcFolder,destFolder);
}catch(IOException e){
e.printStackTrace();
//error, just exit
System.exit(0);
}
}
System.out.println("Done");
}
public static void copyFolder(File src, File dest)
throws IOException{
if(src.isDirectory()){
//if directory not exists, create it
if(!dest.exists()){
dest.mkdir();
System.out.println("Directory copied from "
+ src + " to " + dest);
}
//list all the directory contents
String files[] = src.list();
for (String file : files) {
//construct the src and dest file structure
File srcFile = new File(src, file);
File destFile = new File(dest, file);
//recursive copy
copyFolder(srcFile,destFile);
}
}else{
//if file, then copy it
//Use bytes stream to support all file types
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
//copy the file content in bytes
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
in.close();
out.close();
System.out.println("File copied from " + src + " to " + dest);
}
}
}
Now, I used the above code to take a copy of "My Documents". But unfortunatly, it ended up with NullPointerException after running for a while.
The reason for the error is it tried to take a copy of "My Music" folder, which is not even inside of the "My Documents" folder. I tested this code in 2 different machines running windows 7, got the same error in both.
A windows specific solution is fine for me, as I am targeting windows machines at the moment. What have I done wrong?
The error I am getting is below
Directory copied from C:\Users\Yohan\Documents\My Music to D:\Test\My Music
Exception in thread "main" java.lang.NullPointerException
at CopyDirectoryExample.copyFolder(CopyDirectoryExample.java:51)
at CopyDirectoryExample.copyFolder(CopyDirectoryExample.java:56)
at CopyDirectoryExample.main(CopyDirectoryExample.java:25)
The reason this isn't working is because "My Music", "My Pictures" (or Images) and other directories are just symbolic links. See this post on how to detect symbolic links: Java 1.6 - determine symbolic links
Unfortunately, these folders (Images, Music, Videos) are NOT considered symbolic links in Java. Using Java 8,
Files.isSymbolicLink(srcFile.toPath())
While return false, and Files.readSymbolicLink(srcFile.toPath()) will fail with an Access Denied Exception.
So you can't process them automatically. Fix your code so that you handle properly the case where srcFile.isDirectory() returns true, but srcFile.listFiles() return null.
On my Windows 8 machine, three folders were in that case. I'm on a French machine, so I got a "Ma Musique" folder that gave null for listFiles. However,
new File("C:\\Users\\<user>\\Music").listFiles()
Does NOT return null. So I'm afraid you'll have to hardcode special code for the three folders (Music, Videos, Images) if you want to copy the data too.
You are not handling the empty directories -- try making the following change,
It will work after making the below change.
//list all the directory contents
String files[] = src.list();
if (files!=null && files.length>0) {
for (String file : files) {
//construct the src and dest file structure
File srcFile = new File(src, file);
File destFile = new File(dest, file);
//recursive copy
copyFolder(srcFile,destFile);
}
}
I'm having the problem of replacing or updating some files within a certain directory inside a jar file.
I've read a few post already. The code (the JarUpdater Class) given at this link Updating .JAR's contents from code
is being very helpful for me to understand the role and the use of ZipInputStream, ZipOutputStream and ZipEntry, etc..
However, when I run it,
I have an EOF Exception
[EDITED by mk7: I found out the jar file was corrupted after I went through it 20 times or so. So after I replaced the jar file with a new one, the EOF Exception went away. The other two problems below still remains unsolved]
these two new xml files only get copied to the "root directory" of the jar file.
these two new xml files NEVER replaced the two original files inside a directory called /conf.
Which lines of code should I change in order to replace the xml files with the new ones?
With the System.out.println, I did see that the while loop steps through every directory and compare at every file as expected. A new temp jar was also created as expected...
I thought the statement "notInFiles = false" would take care of my need but it's NOT.
How do I step into the /conf and only replace those two files and NOT leave a copy at the root of the jar file?
What am I missing? Thanks for any insight!
Below are the code from that link.
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class JarUpdater {
public static void main(String[] args) {
File[] contents = {new File("abc.xml"),
new File("def.xml")};
File jarFile = new File("xyz.jar");
try {
updateZipFile(jarFile, contents);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void updateZipFile(File jarFile,
File[] contents) throws IOException {
// get a temp file
File tempFile = File.createTempFile(jarFile.getName(), null);
// delete it, otherwise you cannot rename your existing zip to it.
tempFile.delete();
System.out.println("tempFile is " + tempFile);
boolean renameOk=jarFile.renameTo(tempFile);
if (!renameOk)
{
throw new RuntimeException("could not rename the file "+jarFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath());
}
byte[] buf = new byte[1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(jarFile));
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
boolean notInFiles = true;
for (File f : contents) {
System.out.println("f is " + f);
if (f.getName().equals(name)) {
// that file is already inside the jar file
notInFiles = false;
System.out.println("file already inside the jar file");
break;
}
}
if (notInFiles) {
System.out.println("name is " + name);
System.out.println("entry is " + entry);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
// Close the streams
zin.close();
// Compress the contents
for (int i = 0; i < contents.length; i++) {
InputStream in = new FileInputStream(contents[i]);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(contents[i].getName()));
// Transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
}
// Complete the ZIP file
out.close();
tempFile.delete();
}
}
In your first cycle (while loop) where you copy the entries which you don't want to replace you don't close the entries in the output zip file. Add out.closeEntry(); like this:
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
// ADD THIS LINE:
out.closeEntry();
Also when you check if an entry is to be replaced, you should compare it to a full path, not just to the name of the file. For example if you want to replace abc.xml which is in the /conf folder, you should compare the entry name to "/conf/abc.xml" and not to "abc.xml".
To properly check if an entry is to be replaced:
String name = entry.getName();
boolean notInFiles = true;
for (File f : contents) {
System.out.println("f is " + f);
if (name.equals("/conf/" + f.getName()) {
// that file is already inside the jar file
notInFiles = false;
System.out.println("file already inside the jar file");
break;
}
}
And when you add the entries to the output which are the replaced files, you also have to specify the entry name having full path, e.g. "/conf/abc.xml" and not just "abc.xml" because it would put "abc.xml" in the root of the output zip.
To do this, start the entry name with "/conf/" like this:
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry("/conf/" + contents[i].getName()));
For URIs with the protocol jar:file: (usable for all zip files), you can use a zip file system.
URI jarUri = new URI("jar:" + jarFile.toURI().toString()); // "jar:file:/C:/../xyz.jar"
Map<String, String> zipProperties = new HashMap<>();
zipProperties.put("encoding", "UTF-8");
try (FileSystem zipFS = FileSystems.newFileSystem(jarUri, zipProperties)) {
for (File file : contents) {
Path updatePath = zipFS.getPath("/" + file.getName());
Files.delete(updatePath);
Files.copy(file.toPath(), updatePath, StandardCopyOption.REPLACE_EXISTING);
}
} // closes.
One way to derive the URI is prefixing "jar:" to a File.toURI().
This is a bit more elegant and abstract, and also allows Files.copy in and out the zip. Something to keep in ones tool chest.
I can't seem to import the packages needed or find any online examples of how to extract a .tar.gz file in java.
What makes it worse is I'm using JSP pages and am having trouble importing packages into my project. I'm copying the .jar's into WebContent/WEB-INF/lib/ and then right clicking on the project and selecting import external jar and importing it. Sometimes the packages resolve, other times they don't. Can't seem to get GZIP to import either. The imports in eclipse for jsp aren't intuitive like they are in normal Java code where you can right click a recognized package and select import.
I've tried the Apache commons library, the ice and another one called JTar. Ice has imported, but I can't find any examples of how to use it?
I guess I need to uncompress the gzipped part first, then open it with the tarstream?
Any help is greatly appreciated.
The accepted answer works fine, but I think it is redundant to have a write to file operation.
You could use something like
TarArchiveInputStream tarInput =
new TarArchiveInputStream(new GZipInputStream(new FileInputStream("Your file name")));
TarArchiveEntry currentEntry = tarInput.getNextTarEntry();
while(currentEntry != null) {
File f = currentEntry.getFile();
// TODO write to file as usual
}
Hope this help.
Maven Repo
Ok, i finally figured this out, here is my code in case this helps anyone in the future.
Its written in Java, using the apache commons io and compress librarys.
File dir = new File("directory/of/.tar.gz/files/here");
File listDir[] = dir.listFiles();
if (listDir.length!=0){
for (File i:listDir){
/* Warning! this will try and extract all files in the directory
if other files exist, a for loop needs to go here to check that
the file (i) is an archive file before proceeding */
if (i.isDirectory()){
break;
}
String fileName = i.toString();
String tarFileName = fileName +".tar";
FileInputStream instream= new FileInputStream(fileName);
GZIPInputStream ginstream =new GZIPInputStream(instream);
FileOutputStream outstream = new FileOutputStream(tarFileName);
byte[] buf = new byte[1024];
int len;
while ((len = ginstream.read(buf)) > 0)
{
outstream.write(buf, 0, len);
}
ginstream.close();
outstream.close();
//There should now be tar files in the directory
//extract specific files from tar
TarArchiveInputStream myTarFile=new TarArchiveInputStream(new FileInputStream(tarFileName));
TarArchiveEntry entry = null;
int offset;
FileOutputStream outputFile=null;
//read every single entry in TAR file
while ((entry = myTarFile.getNextTarEntry()) != null) {
//the following two lines remove the .tar.gz extension for the folder name
String fileName = i.getName().substring(0, i.getName().lastIndexOf('.'));
fileName = fileName.substring(0, fileName.lastIndexOf('.'));
File outputDir = new File(i.getParent() + "/" + fileName + "/" + entry.getName());
if(! outputDir.getParentFile().exists()){
outputDir.getParentFile().mkdirs();
}
//if the entry in the tar is a directory, it needs to be created, only files can be extracted
if(entry.isDirectory){
outputDir.mkdirs();
}else{
byte[] content = new byte[(int) entry.getSize()];
offset=0;
myTarFile.read(content, offset, content.length - offset);
outputFile=new FileOutputStream(outputDir);
IOUtils.write(content,outputFile);
outputFile.close();
}
}
//close and delete the tar files, leaving the original .tar.gz and the extracted folders
myTarFile.close();
File tarFile = new File(tarFileName);
tarFile.delete();
}
}
I am trying to unzip a zip file which is stored in the raw folder. Code is as follows
try
{
File myDir = new File(getFilesDir().getAbsolutePath());
File newFile = new File(myDir + "/imageFolder");
if(!newFile.exists())
{
newFile.mkdir();
}
ZipInputStream zipIs = new ZipInputStream(con
.getResources().openRawResource(R.raw.images));
ZipEntry ze = null;
while ((ze = zipIs.getNextEntry()) != null)
{
Log.v("Name", ze.getName());
Log.v("Size", "" + ze.getSize());
if(ze.getSize() >0)
{
FileOutputStream fout = new FileOutputStream(newFile
+ "/" + ze.getName());
byte[] buffer = new byte[1024];
int length = 0;
while ((length = zipIs.read(buffer)) > 0)
{
fout.write(buffer, 0, length);
}
zipIs.closeEntry();
fout.close();
}
}
zipIs.close();
} catch (Exception e)
{
e.printStackTrace();
}
But I keep getting this error
01-18 11:24:28.301: W/System.err(2285): java.io.FileNotFoundException:
/data/data/com.example.ziptests/files/imageFolder/TestImages/background.png
(Not a directory)
I have absolutely no idea why it is causing this, it finds the files, but when it comes to writing them out, it brings up that error. Originally I found a problem that was caused by having the zip file zipped up on the mac, so I zipped up the file on my windows machine instead, that got rid of one problem (when you zip on a mac, it adds these extra folders and files such s store.ds which causes an error when trying to unzip), but this not a directory error keeps coming up.
Any ideas why this is happening?
Please try below link code for unzip zip file.
Code for Extract Zip File
Unzip Zip File
The Problem is I am Uploading zip File which is not made using winrar software, so it is not proper extracted and give me error.
It will solve your problem.
You can't write files to the raw folder. It is a read only dir intended to contain resource files included in your apk.
UPDATE
That file would be better in the assets directory. You can access it through the AssetManager. If not, leave it in the res/raw dir, but access it through Resources.openRawResource. Either way they are Read-Only.
This is my requirement I have one folder(say: Main folder) which contains three items
One folder and two text files
I want to zip only these three items contained in the Main folder .Right now I am zipping the contents with the Main folder and the resultant zipped folder name is "temp.zip",when I unzip this,I am getting the "Main folder". But my requirement is when I unzip the "temp.zip",it should display only the contents of the Main folder.
Could any one help me in achieving this?
Thank you.
Edit :This is the code I am using to zip the files
This is the code I am zipping the files
public void zipFolder(String srcFolder, String destZipFile)
throws Exception {
ZipOutputStream zip = null;
FileOutputStream fileWriter = null;
fileWriter = new FileOutputStream(destZipFile);
zip = new ZipOutputStream(fileWriter);
addFolderToZip("", srcFolder, zip);
zip.flush();
zip.close();
}
private void addFolderToZip(String path, String srcFolder,
ZipOutputStream zip) throws Exception {
File folder = new File(srcFolder);
for (String fileName : folder.list()) {
if (path.equals("")) {
addFileToZip(folder.getName(), srcFolder + "/" + fileName, zip);
} else {
addFileToZip(path + "/" + folder.getName(), srcFolder + "/"
+ fileName, zip);
}
}
}
private void addFileToZip(String path, String srcFile, ZipOutputStream zip)
throws Exception {
File folder = new File(srcFile);
if (folder.isDirectory()) {
addFolderToZip(path, srcFile, zip);
} else {
byte[] buf = new byte[1024];
int len;
FileInputStream in = new FileInputStream(srcFile);
zip.putNextEntry(new ZipEntry(path + "/" + folder.getName()));
while ((len = in.read(buf)) > 0) {
zip.write(buf, 0, len);
}
}
}
I am calling the zipfolder method with these params :
zipFolder(srcfolder, destipath + "/" + "temp.zip");
Zipping a set of individual files into a single zip in Android should be pretty straight forward. There's a pretty good tutorial here that should get you started:
http://www.jondev.net/articles/Zipping_Files_with_Android_%28Programmatically%29
I just copied from this post
Referred from the matt answer I successfully used this library.
You can try Zip4j, a pure java library to handle zip file. It supports
encryption/decryption of PKWare and AES encryption methods.
http://www.lingala.net/zip4j/
Key features:
Create, Add, Extract, Update, Remove files from a Zip file
Read/Write password protected Zip files
Supports AES 128/256 Encryption
Supports Standard Zip Encryption
Supports Zip64 format
Supports Store (No Compression) and Deflate compression method
Create or extract files from Split Zip files (Ex: z01, z02,...zip)
Supports Unicode file names
Progress Monitor
License:
Zip4j is released under Apache License, Version 2.0
try {
String zipFile = "/locations/data.zip";
String srcFolder = "/locations";
File folder = new File(srcFolder);
String[] sourceFiles = folder.list();
//create byte buffer
byte[] buffer = new byte[1024];
/*
* To create a zip file, use
*
* ZipOutputStream(OutputStream out) constructor of ZipOutputStream
* class.
*/
//create object of FileOutputStream
FileOutputStream fout = new FileOutputStream(zipFile);
//create object of ZipOutputStream from FileOutputStream
ZipOutputStream zout = new ZipOutputStream(fout);
for (int i = 0; i < sourceFiles.length; i++) {
if (sourceFiles[i].equalsIgnoreCase("file.csv") || sourceFiles[i].equalsIgnoreCase("file1.csv")) {
sourceFiles[i] = srcFolder + fs + sourceFiles[i];
System.out.println("Adding " + sourceFiles[i]);
//create object of FileInputStream for source file
FileInputStream fin = new FileInputStream(sourceFiles[i]);
/*
* To begin writing ZipEntry in the zip file, use
*
* void putNextEntry(ZipEntry entry) method of
* ZipOutputStream class.
*
* This method begins writing a new Zip entry to the zip
* file and positions the stream to the start of the entry
* data.
*/
zout.putNextEntry(new ZipEntry(sourceFiles[i].substring(sourceFiles[i].lastIndexOf("/") + 1)));
/*
* After creating entry in the zip file, actually write the
* file.
*/
int length;
while ((length = fin.read(buffer)) > 0) {
zout.write(buffer, 0, length);
}
/*
* After writing the file to ZipOutputStream, use
*
* void closeEntry() method of ZipOutputStream class to
* close the current entry and position the stream to write
* the next entry.
*/
zout.closeEntry();
//close the InputStream
fin.close();
}
}
//close the ZipOutputStream
zout.close();
System.out.println("Zip file has been created!");
} catch (IOException ioe) {
System.out.println("IOException :" + ioe);
}
In windows you can achieve this by the following steps,
1.Open the main folder and select the files which you want to add into zip file
2.Right click -> Add to archieve
3.Choose the archieve format as zip and click 'Ok'