Java Exclude Base Directory from Namespace - java

I am trying to programmatically create a runnable jar file. I am using the following code:
The add method:
private static void add(File source, JarOutputStream target) throws IOException
{
BufferedInputStream in = null;
try
{
if (source.isDirectory())
{
String name = source.getPath().replace("\\", File.separator);
if (!name.isEmpty())
{
if (!name.endsWith(File.separator))
name += File.separator;
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
//target.closeEntry();
}
for (File nestedFile: source.listFiles())
add(nestedFile, target);
return;
}
JarEntry entry = new JarEntry(source.getPath().replace("\\", "/"));
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true)
{
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
}
finally
{
if (in != null)
in.close();
}
}
Its implementation:
try {
File[] files = new File("tmp").listFiles();
for (File file : files) {
System.out.println("Archiving: "+file.getName());
add(file, target);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
target.close();
} catch (IOException e) {
e.printStackTrace();
}
I am trying to add all of the contents of the tmp directory to my jar, but I do not want to prefix all of the namespaces with tmp.. I tried using this code to iterate through the the files in tmp and add them but I keep getting errors saying "no such file or directory". I am pretty sure that's because it is looking outside the tmp directory. However, when I change it to add(new File("tmp"+File.separator+file.getName()), target); I end up with "tmp" in my namespaces (because I started with the tmp/ directory). Is there a way around this?
Here is an example:
I have a jar file with the Main-Class attribute com.name.proj.ProjDriver
When I decompress it into the tmp folder I end up with the file in tmp/com/name/proj/ProjDriver.class. I then recompress my jar using the manifest object from the old jar still specifying the main class as com.name.proj.ProjDriver but now it is actually tmp.com.name.proj.ProjDriver. How can I avoid having tmp. as a prefix for all the namespaces?

Replace your code with this:
private static void add(File source, JarOutputStream target) throws IOException
{
BufferedInputStream in = null;
try
{
if (source.isDirectory())
{
String name = source.getPath().replace("\\", File.separator);
if (!name.isEmpty())
{
if (!name.endsWith(File.separator))
name += File.separator;
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
//target.closeEntry();
}
for (File nestedFile: source.listFiles())
try{add(nestedFile, target);}catch(IOException e){System.out.println(e);}
return;
}
JarEntry entry = new JarEntry(source.getPath().replace("tmp\\","").replace("\\", "/"));
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true)
{
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
}
finally
{
if (in != null)
in.close();
}
}
I have varied this row:
JarEntry entry = new JarEntry(source.getPath().replace("tmp\\","").replace("\\", "/"));

Related

How to create a .tar.gz file, RETAINING the same folder/directory structure, in Java

I am looking to create a .tar.gz file of the following folder/directory structure, while retaining the same folder/ directory structure
ParentDir\
ChildDir1\
-file1
ChildDir2\
-file2
-file3
ChildDir3\
-file4
-file5
However I am only able to create a .tar.gz of all the files, without the folder/directory structure.
ie: ParentDir.tar.gz
ParentDir\
-file1
-file2
-file3
-file4
-file5
Using the user accepted answer in Compress directory to tar.gz with Commons Compress, I have the following code:
public void exportStaticFilesTar(String appID) throws, Exception {
FileOutputStream fOut = null;
BufferedOutputStream bOut = null;
GzipCompressorOutputStream gzOut = null;
TarArchiveOutputStream tOut = null;
try {
String filename = "ParentDir.tar.gz"
//"parent/childDirToCompress/"
String path = "<path to ParentDir>";
fOut = new FileOutputStream(new File(filename));
bOut = new BufferedOutputStream(fOut);
gzOut = new GzipCompressorOutputStream(bOut);
tOut = new TarArchiveOutputStream(gzOut);
addFileToTarGz(tOut, path, "");
} catch (Exception e) {
log.error("Error creating .tar.gz: " +e);
} finally {
tOut.finish();
tOut.close();
gzOut.close();
bOut.close();
fOut.close();
}
//Download the file locally
}
private void addFileToTarGz(TarArchiveOutputStream tOut, String path, String base) throws IOException {
File f = new File(path);
String entryName = base + f.getName();
TarArchiveEntry tarEntry = new TarArchiveEntry(f, entryName);
tOut.putArchiveEntry(tarEntry);
if (f.isFile()) {
IOUtils.copy(new FileInputStream(f), tOut);
tOut.closeArchiveEntry();
} else {
tOut.closeArchiveEntry();
File[] children = f.listFiles();
if (children != null) {
for (File child : children) {
addFileToTarGz(tOut, child.getAbsolutePath(), entryName + "/");
}
}
}
}
Can someone please advice, how I can modify the current code to retain the folder/directory structure when creating a .tar.gz file. Thanks!
I get on better with the following. Important: you need to pass as base the correct initial value which is the first directory in the tree (excluding the fs root):
private void addFileToTarGz(TarArchiveOutputStream tOut, String path, String base) throws IOException {
File f = new File(path);
String entryName = base + File.separatorChar + f.getName();
TarArchiveEntry tarEntry = new TarArchiveEntry(f, entryName);
tOut.putArchiveEntry(tarEntry);
if (f.isFile()) {
IOUtils.copy(new FileInputStream(f), tOut);
tOut.closeArchiveEntry();
} else {
tOut.closeArchiveEntry();
File[] children = f.listFiles();
if (children != null) {
for (File child : children) {
addFileToTarGz(tOut, child.getAbsolutePath(), entryName);
}
}
}
}
Using the code mentioned in the request, I was able to generate a successful compressed file on my linux system.
You can replicate by changing user path and the root folder which needs to be compressed.
public static void createTarGZ() throws FileNotFoundException, IOException
{
String sourceDirectoryPath = null;
String destinationTarGzPath = null;
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
GzipCompressorOutputStream gzOutpuStream = null;
TarArchiveOutputStream tarArchiveOutputStream = null;
String basePath = "/home/saad/CompressionTest/";
try
{
sourceDirectoryPath = basePath + "asterisk";
destinationTarGzPath = basePath + "asterisk.tar.gz";
fileOutputStream = new FileOutputStream(new File(destinationTarGzPath));
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
gzOutpuStream = new GzipCompressorOutputStream(bufferedOutputStream);
tarArchiveOutputStream = new TarArchiveOutputStream(gzOutpuStream);
addFileToTarGz(tarArchiveOutputStream, sourceDirectoryPath, "");
}
finally
{
tarArchiveOutputStream.finish();
tarArchiveOutputStream.close();
gzOutpuStream.close();
bufferedOutputStream.close();
fileOutputStream.close();
}
}
private static void addFileToTarGz(TarArchiveOutputStream tarOutputStream, String path, String base) throws IOException
{
File fileToCompress = new File(path);
String entryName = base + fileToCompress.getName();
TarArchiveEntry tarEntry = new TarArchiveEntry(fileToCompress, entryName);
tarOutputStream.putArchiveEntry(tarEntry);
// If its a file, simply add it
if (fileToCompress.isFile())
{
IOUtils.copy(new FileInputStream(fileToCompress), tarOutputStream);
tarOutputStream.closeArchiveEntry();
}
// If its a folder then add all its contents
else
{
tarOutputStream.closeArchiveEntry();
File[] children = fileToCompress.listFiles();
if (children != null)
{
// add every file/folder recursively to the tar
for (File child : children)
{
addFileToTarGz(tarOutputStream, child.getAbsolutePath(), entryName + "/");
}
}
}
}

Create a Fat-Jar Programmatically

I am trying to create a fat-jar programmatically. So far, I managed to create a Jar file with my code inside. The problem is that, if I run this, I receive an exception saying Cannot load user class: org.company.bla.bla.
Here is my code
private static void createJar() throws IOException {
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
JarOutputStream target = new JarOutputStream(new FileOutputStream("events.jar"), manifest);
Path root = Paths.get(".").normalize().toAbsolutePath();
System.out.println(root.toString());
Files.walk(root).forEach(f -> add(f.toFile(), target));
target.close();
}
private static void add(File source, JarOutputStream target)
{
BufferedInputStream in = null;
try {
if (source.isDirectory()) {
String name = source.getPath().replace("\\", "/");
if (!name.isEmpty()) {
if (!name.endsWith("/"))
name += "/";
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
target.closeEntry();
}
for (File nestedFile: source.listFiles())
add(nestedFile, target);
return;
}
JarEntry entry = new JarEntry(source.getPath().replace("\\", "/"));
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true) {
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
How can I also add the dependencies to this Jar? Or where is the path where the dependencies are so I can include them?

include external library inside programmatically created jar

I have a java program that is created using jaroutput stream. and the output jar uses an external library.
At first I thought that I could use classpath in the manifest to get the external library inside the jar.
Then I found out that that doesnt work.
Then I thought about custom class loaders such as one-jar.
but I got stuck trying to get it to work in a generated jar.
External library is jsonsimple 1.1.1 if you are wondering.
and here is the code for the generated custom jar.
public void run(String output) throws IOException {
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, "Install");
manifest.getMainAttributes().put(Attributes.Name.CLASS_PATH, "json-simple-1.1.1.jar");
JarOutputStream target = new JarOutputStream(new FileOutputStream(output), manifest);
add(tempclass, target,"Install.class");
add(tempjar, target,"lib/json-simple-1.1.1.jar");
if (resourcepackzip != null) {
add(resourcepackzip, target,resourcepackzip.getName().toString());
}
if (optionstxt != null){
add(optionstxt, target,optionstxt.getName().toString());
}
add(worldzip, target,worldzip.getName().toString());
add(temptxt, target,temptxt.getName().toString());
target.close();
}
#SuppressWarnings("resource")
private void add(File source, JarOutputStream target,String source2) throws IOException
{
BufferedInputStream in = null;
try
{
if (source.isDirectory())
{
String name = source.getPath().replace("\\", "/");
if (!name.isEmpty())
{
if (!name.endsWith("/"))
name += "/";
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
target.closeEntry();
}
for (File nestedFile: source.listFiles())
add(nestedFile, target, nestedFile.getName().toString());
return;
}
JarEntry entry = new JarEntry(source2);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true)
{
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
}finally {
}
}
So is there anyway I can include json in a jar made with jaroutputstream?

Maven: iterate a directory of files inside Maven's resource directory

I have a set of files in my Maven resource folder:
+ src
+ main
+ resources
+ mydir
+ myfile1.txt
+ myfile2.txt
How can I iterate mydir? Not only in Eclipse, but when running JUnit tests from the command line, and from a dependent jar.
File mydir = new File("mydir");
for (File f : dir.listFiles()) {
dosomething...
}
Thanks for a hint!
Nutshell, roughly:
URL pathUrl = clazz.getClassLoader().getResource("mydir/");
if ((pathURL != null) && pathUrl.getProtocol().equals("file")) {
return new File(pathUrl.toURI()).list();
}
Tested; Groovy:
def resourcesInDir(String dir) {
def ret = []
pathUrl = this.class.getClassLoader().getResource(dir)
if ((pathUrl != null) && pathUrl.getProtocol().equals("file")) {
new File(pathUrl.toURI()).list().each {
ret << "${dir}/${it}"
}
}
ret
}
files = resourcesInDir("tmp/")
files.each {
s = this.class.getResourceAsStream(it)
println s.text
}
In the end, this is what I came up with to handle accessing files within referenced jars:
public class ResourceHelper {
public static File getFile(String resourceOrFile)
throws FileNotFoundException {
try {
// jar:file:/home/.../blue.jar!/path/to/file.xml
URI uri = getURL(resourceOrFile).toURI();
String uriStr = uri.toString();
if (uriStr.startsWith("jar")) {
if (uriStr.endsWith("/")) {
throw new UnsupportedOperationException(
"cannot unjar directories, only files");
}
String jarPath = uriStr.substring(4, uriStr.indexOf("!"))
.replace("file:", "");
String filePath = uriStr.substring(uriStr.indexOf("!") + 2);
JarFile jarFile = new JarFile(jarPath);
assert (jarFile.size() > 0) : "no jarFile at " + jarPath;
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (jarEntry.toString().equals(filePath)) {
InputStream input = jarFile.getInputStream(jarEntry);
assert (input != null) : "empty is for " + jarEntry;
return tmpFileFromStream(input, filePath);
}
}
assert (false) : "file" + filePath + " not found in " + jarPath;
return null;
} else {
return new File(uri);
}
} catch (URISyntaxException e) {
throw new FileNotFoundException(resourceOrFile);
} catch (IOException e) {
throw new FileNotFoundException(resourceOrFile);
}
}
private static File tmpFileFromStream(InputStream is, String filePath)
throws IOException {
String fileName = filePath.substring(filePath.lastIndexOf("/") + 1,
filePath.lastIndexOf("."));
assert (fileName != null) : "filename cannot be null for " + filePath;
String extension = filePath.substring(filePath.lastIndexOf("."));
assert (extension != null) : "extension cannot be null for " + filePath;
File tmpFile = File.createTempFile(fileName, extension);
// tempFile.deleteOnExit();
assert (tmpFile.exists()) : "could not create tempfile";
OutputStream out = new FileOutputStream(tmpFile);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = is.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
is.close();
out.flush();
out.close();
assert (tmpFile.length() > 0) : "file empty "
+ tmpFile.getAbsolutePath();
return tmpFile;
}
public static File getTempFile(String resourceOrFile) throws IOException {
InputStream input = getInputStream(resourceOrFile);
File tempFile = IOUtils.createTempDir();
tempFile.deleteOnExit();
FileOutputStream output = new FileOutputStream(tempFile);
byte[] buffer = new byte[4096];
int bytesRead = input.read(buffer);
while (bytesRead != -1) {
output.write(buffer, 0, bytesRead);
bytesRead = input.read(buffer);
}
output.close();
input.close();
return tempFile;
}
public static InputStream getInputStream(String resourceOrFile)
throws FileNotFoundException {
try {
return getURL(resourceOrFile).openStream();
} catch (Exception e) {
throw new FileNotFoundException(resourceOrFile);
}
}
public static URL getURL(String resourceOrFile)
throws FileNotFoundException {
File file = new File(resourceOrFile);
// System.out.println("checking file ");
// is file
if (file.exists()) {
// System.out.println("file exists");
try {
return file.toURI().toURL();
} catch (MalformedURLException e) {
throw new FileNotFoundException(resourceOrFile);
}
}
// is resource
if (!file.exists()) {
// System.out.println("file resource");
URL url = Thread.class.getResource(resourceOrFile);
if (url != null) {
return url;
}
url = Thread.class.getResource("/" + resourceOrFile);
if (url != null) {
return url;
}
}
throw new FileNotFoundException(resourceOrFile);
}
}

How to create a zip file in Java

I have a dynamic text file that picks content from a database according to the user's query. I have to write this content into a text file and zip it in a folder in a servlet. How should I do this?
Look at this example:
StringBuilder sb = new StringBuilder();
sb.append("Test String");
File f = new File("d:\\test.zip");
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f));
ZipEntry e = new ZipEntry("mytext.txt");
out.putNextEntry(e);
byte[] data = sb.toString().getBytes();
out.write(data, 0, data.length);
out.closeEntry();
out.close();
This will create a zip in the root of D: named test.zip which will contain one single file called mytext.txt. Of course you can add more zip entries and also specify a subdirectory like this:
ZipEntry e = new ZipEntry("folderName/mytext.txt");
You can find more information about compression with Java here.
Java 7 has ZipFileSystem built in, that can be used to create, write and read file from zip file.
Java Doc: ZipFileSystem Provider
Map<String, String> env = new HashMap<>();
// Create the zip file if it doesn't exist
env.put("create", "true");
URI uri = URI.create("jar:file:/codeSamples/zipfs/zipfstest.zip");
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
Path externalTxtFile = Paths.get("/codeSamples/zipfs/SomeTextFile.txt");
Path pathInZipfile = zipfs.getPath("/SomeTextFile.txt");
// Copy a file into the zip file
Files.copy(externalTxtFile, pathInZipfile, StandardCopyOption.REPLACE_EXISTING);
}
To write a ZIP file, you use a ZipOutputStream. For each entry that you want to place into the ZIP file, you create a ZipEntry object. You pass the file name to the ZipEntry constructor; it sets the other parameters such as file date and decompression method. You can override these settings if you like. Then, you call the putNextEntry method of the ZipOutputStream to begin writing a new file. Send the file data to the ZIP stream. When you are done, call closeEntry. Repeat for all the files you want to store. Here is a code skeleton:
FileOutputStream fout = new FileOutputStream("test.zip");
ZipOutputStream zout = new ZipOutputStream(fout);
for all files
{
ZipEntry ze = new ZipEntry(filename);
zout.putNextEntry(ze);
send data to zout;
zout.closeEntry();
}
zout.close();
Here is an example code to compress a Whole Directory(including sub files and sub directories), it's using the walk file tree feature of Java NIO.
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipCompress {
public static void compress(String dirPath) {
final Path sourceDir = Paths.get(dirPath);
String zipFileName = dirPath.concat(".zip");
try {
final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) {
try {
Path targetFile = sourceDir.relativize(file);
outputStream.putNextEntry(new ZipEntry(targetFile.toString()));
byte[] bytes = Files.readAllBytes(file);
outputStream.write(bytes, 0, bytes.length);
outputStream.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
return FileVisitResult.CONTINUE;
}
});
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
To use this, just call
ZipCompress.compress("target/directoryToCompress");
and you'll get a zip file directoryToCompress.zip
Single file:
String filePath = "/absolute/path/file1.txt";
String zipPath = "/absolute/path/output.zip";
try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipPath))) {
File fileToZip = new File(filePath);
zipOut.putNextEntry(new ZipEntry(fileToZip.getName()));
Files.copy(fileToZip.toPath(), zipOut);
}
Multiple files:
List<String> filePaths = Arrays.asList("/absolute/path/file1.txt", "/absolute/path/file2.txt");
String zipPath = "/absolute/path/output.zip";
try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipPath))) {
for (String filePath : filePaths) {
File fileToZip = new File(filePath);
zipOut.putNextEntry(new ZipEntry(fileToZip.getName()));
Files.copy(fileToZip.toPath(), zipOut);
}
}
Spring boot controller, zip the files in a directory, and can be downloaded.
#RequestMapping(value = "/files.zip")
#ResponseBody
byte[] filesZip() throws IOException {
File dir = new File("./");
File[] filesArray = dir.listFiles();
if (filesArray == null || filesArray.length == 0)
System.out.println(dir.getAbsolutePath() + " have no file!");
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ZipOutputStream zipOut= new ZipOutputStream(bo);
for(File xlsFile:filesArray){
if(!xlsFile.isFile())continue;
ZipEntry zipEntry = new ZipEntry(xlsFile.getName());
zipOut.putNextEntry(zipEntry);
zipOut.write(IOUtils.toByteArray(new FileInputStream(xlsFile)));
zipOut.closeEntry();
}
zipOut.close();
return bo.toByteArray();
}
This is how you create a zip file from a source file:
String srcFilename = "C:/myfile.txt";
String zipFile = "C:/myfile.zip";
try {
byte[] buffer = new byte[1024];
FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zos = new ZipOutputStream(fos);
File srcFile = new File(srcFilename);
FileInputStream fis = new FileInputStream(srcFile);
zos.putNextEntry(new ZipEntry(srcFile.getName()));
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
zos.close();
}
catch (IOException ioe) {
System.out.println("Error creating zip file" + ioe);
}
public static void main(String args[])
{
omtZip("res/", "omt.zip");
}
public static void omtZip(String path,String outputFile)
{
final int BUFFER = 2048;
boolean isEntry = false;
ArrayList<String> directoryList = new ArrayList<String>();
File f = new File(path);
if(f.exists())
{
try {
FileOutputStream fos = new FileOutputStream(outputFile);
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos));
byte data[] = new byte[BUFFER];
if(f.isDirectory())
{
//This is Directory
do{
String directoryName = "";
if(directoryList.size() > 0)
{
directoryName = directoryList.get(0);
System.out.println("Directory Name At 0 :"+directoryName);
}
String fullPath = path+directoryName;
File fileList = null;
if(directoryList.size() == 0)
{
//Main path (Root Directory)
fileList = f;
}else
{
//Child Directory
fileList = new File(fullPath);
}
String[] filesName = fileList.list();
int totalFiles = filesName.length;
for(int i = 0 ; i < totalFiles ; i++)
{
String name = filesName[i];
File filesOrDir = new File(fullPath+name);
if(filesOrDir.isDirectory())
{
System.out.println("New Directory Entry :"+directoryName+name+"/");
ZipEntry entry = new ZipEntry(directoryName+name+"/");
zos.putNextEntry(entry);
isEntry = true;
directoryList.add(directoryName+name+"/");
}else
{
System.out.println("New File Entry :"+directoryName+name);
ZipEntry entry = new ZipEntry(directoryName+name);
zos.putNextEntry(entry);
isEntry = true;
FileInputStream fileInputStream = new FileInputStream(filesOrDir);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, BUFFER);
int size = -1;
while( (size = bufferedInputStream.read(data, 0, BUFFER)) != -1 )
{
zos.write(data, 0, size);
}
bufferedInputStream.close();
}
}
if(directoryList.size() > 0 && directoryName.trim().length() > 0)
{
System.out.println("Directory removed :"+directoryName);
directoryList.remove(0);
}
}while(directoryList.size() > 0);
}else
{
//This is File
//Zip this file
System.out.println("Zip this file :"+f.getPath());
FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis,BUFFER);
ZipEntry entry = new ZipEntry(f.getName());
zos.putNextEntry(entry);
isEntry = true;
int size = -1 ;
while(( size = bis.read(data,0,BUFFER)) != -1)
{
zos.write(data, 0, size);
}
}
//CHECK IS THERE ANY ENTRY IN ZIP ? ----START
if(isEntry)
{
zos.close();
}else
{
zos = null;
System.out.println("No Entry Found in Zip");
}
//CHECK IS THERE ANY ENTRY IN ZIP ? ----START
}catch(Exception e)
{
e.printStackTrace();
}
}else
{
System.out.println("File or Directory not found");
}
}
}
Given exportPath and queryResults as String variables, the following block creates a results.zip file under exportPath and writes the content of queryResults to a results.txt file inside the zip.
URI uri = URI.create("jar:file:" + exportPath + "/results.zip");
Map<String, String> env = Collections.singletonMap("create", "true");
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
Path filePath = zipfs.getPath("/results.txt");
byte[] fileContent = queryResults.getBytes();
Files.write(filePath, fileContent, StandardOpenOption.CREATE);
}
You have mainly to create two functions. First is writeToZipFile() and second is createZipfileForOutPut .... and then call the createZipfileForOutPut('file name of .zip')` …
public static void writeToZipFile(String path, ZipOutputStream zipStream)
throws FileNotFoundException, IOException {
System.out.println("Writing file : '" + path + "' to zip file");
File aFile = new File(path);
FileInputStream fis = new FileInputStream(aFile);
ZipEntry zipEntry = new ZipEntry(path);
zipStream.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipStream.write(bytes, 0, length);
}
zipStream.closeEntry();
fis.close();
}
public static void createZipfileForOutPut(String filename) {
String home = System.getProperty("user.home");
// File directory = new File(home + "/Documents/" + "AutomationReport");
File directory = new File("AutomationReport");
if (!directory.exists()) {
directory.mkdir();
}
try {
FileOutputStream fos = new FileOutputStream("Path to your destination" + filename + ".zip");
ZipOutputStream zos = new ZipOutputStream(fos);
writeToZipFile("Path to file which you want to compress / zip", zos);
zos.close();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
There is another option by using zip4j at https://github.com/srikanth-lingala/zip4j
Creating a zip file with single file in it / Adding single file to an existing zip
new ZipFile("filename.zip").addFile("filename.ext");
Or
new ZipFile("filename.zip").addFile(new File("filename.ext"));
Creating a zip file with multiple files / Adding multiple files to an existing zip
new ZipFile("filename.zip").addFiles(Arrays.asList(new File("first_file"), new File("second_file")));
Creating a zip file by adding a folder to it / Adding a folder to an existing zip
new ZipFile("filename.zip").addFolder(new File("/user/myuser/folder_to_add"));
Creating a zip file from stream / Adding a stream to an existing zip
new ZipFile("filename.zip").addStream(inputStream, new ZipParameters());
I know this question is answered but if you have a list of strings and you want to create a separate file for each string in the archive, you can use the snippet below.
public void zipFileTest() throws IOException {
Map<String, String> map = Map.ofEntries(
new AbstractMap.SimpleEntry<String, String>("File1.txt", "File1 Content"),
new AbstractMap.SimpleEntry<String, String>("File2.txt", "File2 Content"),
new AbstractMap.SimpleEntry<String, String>("File3.txt", "File3 Content")
);
createZipFileFromStringContents(map, "archive.zip");
}
public void createZipFileFromStringContents(Map<String, String> map, String zipfilePath) throws IOException {
FileOutputStream fout = new FileOutputStream(zipfilePath);
ZipOutputStream zout = new ZipOutputStream(fout);
for (Map.Entry<String, String> entry : map.entrySet()) {
String fileName = entry.getKey();
ZipEntry zipFile = new ZipEntry(fileName);
zout.putNextEntry(zipFile);
String fileContent = entry.getValue();
zout.write(fileContent.getBytes(), 0, fileContent.getBytes().length);
zout.closeEntry();
}
zout.close();
}
It will create a zip file with the structure as in the below image:
Here is my working solution:
public static byte[] createZipFile(Map<String, FileData> files) throws IOException {
try(ByteArrayOutputStream tZipFile = new ByteArrayOutputStream()) {
try (ZipOutputStream tZipFileOut = new ZipOutputStream(tZipFile)) {
for (Map.Entry<String, FileData> file : files.entrySet()) {
ZipEntry zipEntry = new ZipEntry(file.getValue().getFileName());
tZipFileOut.putNextEntry(zipEntry);
tZipFileOut.write(file.getValue().getBytes());
}
}
return tZipFile.toByteArray();
}
}
public class FileData {
private String fileName;
private byte[] bytes;
public String getFileName() {
return this.fileName;
}
public byte[] getBytes() {
return this.bytes;
}
}
This will create byte[] of ZIP file which contains one or more compressed files. I've used this method inside controller method and write bytes[] of ZIP file into response to download ZIP file(s) from server.
Since it took me a while to figure it out, I thought it would be helpful to post my solution using Java 7+ ZipFileSystem
openZip(runFile);
addToZip(filepath); //loop construct;
zipfs.close();
private void openZip(File runFile) throws IOException {
Map<String, String> env = new HashMap<>();
env.put("create", "true");
env.put("encoding", "UTF-8");
Files.deleteIfExists(runFile.toPath());
zipfs = FileSystems.newFileSystem(URI.create("jar:" + runFile.toURI().toString()), env);
}
private void addToZip(String filename) throws IOException {
Path externalTxtFile = Paths.get(filename).toAbsolutePath();
Path pathInZipfile = zipfs.getPath(filename.substring(filename.lastIndexOf("results"))); //all files to be stored have a common base folder, results/ in my case
if (Files.isDirectory(externalTxtFile)) {
Files.createDirectories(pathInZipfile);
try (DirectoryStream<Path> ds = Files.newDirectoryStream(externalTxtFile)) {
for (Path child : ds) {
addToZip(child.normalize().toString()); //recursive call
}
}
} else {
// copy file to zip file
Files.copy(externalTxtFile, pathInZipfile, StandardCopyOption.REPLACE_EXISTING);
}
}
public static void zipFromTxt(String zipFilePath, String txtFilePath) {
Assert.notNull(zipFilePath, "Zip file path is required");
Assert.notNull(txtFilePath, "Txt file path is required");
zipFromTxt(new File(zipFilePath), new File(txtFilePath));
}
public static void zipFromTxt(File zipFile, File txtFile) {
ZipOutputStream out = null;
FileInputStream in = null;
try {
Assert.notNull(zipFile, "Zip file is required");
Assert.notNull(txtFile, "Txt file is required");
out = new ZipOutputStream(new FileOutputStream(zipFile));
in = new FileInputStream(txtFile);
out.putNextEntry(new ZipEntry(txtFile.getName()));
int len;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
out.flush();
}
} catch (Exception e) {
log.info("Zip from txt occur error,Detail message:{}", e.toString());
} finally {
try {
if (in != null) in.close();
if (out != null) {
out.closeEntry();
out.close();
}
} catch (Exception e) {
log.info("Zip from txt close error,Detail message:{}", e.toString());
}
}
}
Using Jeka https://jeka.dev JkPathTree, it's quite straightforward.
Path wholeDirToZip = Paths.get("dir/to/zip");
Path zipFile = Paths.get("file.zip");
JkPathTree.of(wholeDirToZip).zipTo(zipFile);
If you want decompress without software better use this code. Other code with pdf files sends error on manually decompress
byte[] buffer = new byte[1024];
try {
FileOutputStream fos = new FileOutputStream("123.zip");
ZipOutputStream zos = new ZipOutputStream(fos);
ZipEntry ze= new ZipEntry("file.pdf");
zos.putNextEntry(ze);
FileInputStream in = new FileInputStream("file.pdf");
int len;
while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
in.close();
zos.closeEntry();
zos.close();
} catch(IOException ex) {
ex.printStackTrace();
}

Categories

Resources