I am trying to implement program to zip and unzip a file. All I want to do is to zip a file (fileName.fileExtension) with name as fileName.zip and on unzipping change it again to fileName.fileExtension.
This is how I used to rename files or change its extension.
public static void modify(File file)
{
int index = file.getName().lastIndexOf(".");
//print filename
//System.out.println(file.getName().substring(0, index));
//print extension
//System.out.println(file.getName().substring(index));
String ext = file.getName().substring(index);
//use file.renameTo() to rename the file
file.renameTo(new File("Newname"+ext));
}
edit: John's method renames the file (keeping the extension). To change the extension do:
public static File changeExtension(File f, String newExtension) {
int i = f.getName().lastIndexOf('.');
String name = f.getName().substring(0,i);
return new File(f.getParent(), name + newExtension);
}
This changes only the last extension to a filename, i.e. the .gz part of archive.tar.gz. Therefore it works fine with Linux hidden files, for which the name starts with a .
This is quite safe because if getParent() returns null (i.e. in the event of the parent being the system root) it is "cast" to an empty String as the whole argument to the File constructor is evaluated first.
The only case where you will get a funny output is if you pass in a File representing the system root itself, in which case the null is prepended to the rest of the path string.
Try with:
File file = new File("fileName.zip"); // handler to your ZIP file
File file2 = new File("fileName.fileExtension"); // destination dir of your file
boolean success = file.renameTo(file2);
if (success) {
// File has been renamed
}
I would check, if the file has an extension before changing. The solution below works also with files without extension or multiple extensions
public File changeExtension(File file, String extension) {
String filename = file.getName();
if (filename.contains(".")) {
filename = filename.substring(0, filename.lastIndexOf('.'));
}
filename += "." + extension;
file.renameTo(new File(file.getParentFile(), filename));
return file;
}
#Test
public void test() {
assertThat(changeExtension(new File("C:/a/aaa.bbb.ccc"), "txt"),
is(new File("C:/a/aaa.bbb.txt")));
assertThat(changeExtension(new File("C:/a/test"), "txt"),
is(new File("C:/a/test.txt")));
}
By the same logic as mentioned #hsz, but instead simply use replacement:
File file = new File("fileName.fileExtension"); // creating object of File
String str = file.getPath().replace(".fileExtension", ".zip"); // replacing extension to another
file.renameTo(new File(str));
I want to avoid the new extension just happening to be in the path or filename itself. I like a combination of java.nio and apache StringFilenameUtils.
public void changeExtension(Path file, String extension) throws IOException {
String newFilename = FilenameUtils.removeExtension(file.toString()) + EXTENSION_SEPARATOR_STR + extension;
Files.move(file, Paths.get(newFilename, StandardCopyOption.REPLACE_EXISTING));
}
If you are using Kotlin you can use from this property of your file object:
file.nameWithoutExtension + "extension"
FilenameUtils.getFullPathNoEndSeparator(doc.getDocLoc()) + "/" +
FilenameUtils.getBaseName(doc.getDocLoc()) + ".xml"
My firend was working on a zipper in Java some 4 months back, I got this code from him.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipFiles {
List<String> filesListInDir = new ArrayList<String>();
public static void main(String[] args) {
File file = new File("/Users/pankaj/sitemap.xml");
String zipFileName = "/Users/pankaj/sitemap.zip";
File dir = new File("/Users/pankaj/tmp");
String zipDirName = "/Users/pankaj/tmp.zip";
zipSingleFile(file, zipFileName);
ZipFiles zipFiles = new ZipFiles();
zipFiles.zipDirectory(dir, zipDirName);
}
/**
* This method zips the directory
* #param dir
* #param zipDirName
*/
private void zipDirectory(File dir, String zipDirName) {
try {
populateFilesList(dir);
//now zip files one by one
//create ZipOutputStream to write to the zip file
FileOutputStream fos = new FileOutputStream(zipDirName);
ZipOutputStream zos = new ZipOutputStream(fos);
for(String filePath : filesListInDir){
System.out.println("Zipping "+filePath);
//for ZipEntry we need to keep only relative file path, so we used substring on absolute path
ZipEntry ze = new ZipEntry(filePath.substring(dir.getAbsolutePath().length()+1, filePath.length()));
zos.putNextEntry(ze);
//read the file and write to ZipOutputStream
FileInputStream fis = new FileInputStream(filePath);
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
zos.closeEntry();
fis.close();
}
zos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* This method populates all the files in a directory to a List
* #param dir
* #throws IOException
*/
private void populateFilesList(File dir) throws IOException {
File[] files = dir.listFiles();
for(File file : files){
if(file.isFile())
filesListInDir.add(file.getAbsolutePath());
else
populateFilesList(file);
}
}
/**
* This method compresses the single file to zip format
* #param file
* #param zipFileName
*/
private static void zipSingleFile(File file, String zipFileName) {
try {
//create ZipOutputStream to write to the zip file
FileOutputStream fos = new FileOutputStream(zipFileName);
ZipOutputStream zos = new ZipOutputStream(fos);
//add a new Zip Entry to the ZipOutputStream
ZipEntry ze = new ZipEntry(file.getName());
zos.putNextEntry(ze);
//read the file and write to ZipOutputStream
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
//Close the zip entry to write to zip file
zos.closeEntry();
//Close resources
zos.close();
fis.close();
fos.close();
System.out.println(file.getCanonicalPath()+" is zipped to "+zipFileName);
} catch (IOException e) {
e.printStackTrace();
}
}
}
I haven't tried it personally, but he and also some of my other friends told me that it works.
Related
My UnZip class does not unzip whole the file. This class is called from another activity. My zip file is saved in the main directory of the phone's internal storage. The zip file has folders and some video.
What's wrong with this unzip?
What and how should I read file from zip' decompress and unzip is the same meaning?
Thanks for your help!
public class Unzip {
private static final String INPUT_ZIP_FILE = "sdcard/downloaded_issue.zip";
private static final String OUTPUT_FOLDER = "sdcard/Atlantis/";
public static void main()
{
Unzip unZip = new Unzip();
unZip.unZipIt(INPUT_ZIP_FILE, OUTPUT_FOLDER);
}
/**
* Unzip it
* #param zipFile input zip file
* #param outputFolder zip file output folder
*/
public void unZipIt(String zipFile, String outputFolder){
byte[] buffer = new byte[1024];
try{
//create output directory is not exists
File folder = new File(OUTPUT_FOLDER);
if(!folder.exists()){
folder.mkdir();
}
//get the zip file content
ZipInputStream zis =
new ZipInputStream(new FileInputStream(zipFile));
//get the zipped file list entry
ZipEntry ze = zis.getNextEntry();
while(ze!=null){
String fileName = ze.getName();
File newFile = new File(outputFolder + File.separator + fileName);
System.out.println("file unzip : "+ newFile.getAbsoluteFile());
//create all non exists folders
//else you will hit FileNotFoundException for compressed folder
new File(newFile.getParent()).mkdirs();
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
if (ze.isDirectory()) {
ze = zis.getNextEntry();
}
}
zis.closeEntry();
zis.close();
System.out.println("Done");
}catch(IOException ex){
ex.printStackTrace();
}
}
}
I think your 'while' loop is broken; you're only fetching the next entry if that next entry is a directory, while I assume you're probably trying to skip the directories.
Anyway, since you create the folders for all files you encounter, you can just skip the folder entries and write the file entries. The only exception would be the creation of empty folders.
Replacing the while-loop by this code should work:
while(ze!=null){
String fileName = ze.getName();
File newFile = new File(outputFolder + File.separator + fileName);
System.out.println("file unzip : "+ newFile.getAbsoluteFile());
//create all non exists folders
//else you will hit FileNotFoundException for compressed folder
if (ze.isDirectory()) {
// create the folder
newFile.mkdirs();
}
else {
// create the parent folder and write to disk
new File(newFile.getParent()).mkdirs();
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
// get the next item
ze = zis.getNextEntry();
}
UPDATE
For issue #2 regarding the folder, I just replaced ZipEntry ze = new ZipEntry(source + File.separator + file); with ZipEntry ze = new ZipEntry(file);.
Issue remains with WINZIP not able to open the zipped file while unzip can unzip the file. WINZIP's error is: Error: unable to seek to beginning of central directory.
ORIGINAL POST
I have the following code that I have gotten and slightly modified from one of the questions on SO. In my application, I set OUTPUT_ZIP_FILE to /var/tmp/test/test.zip and my source folder as /var/tmp/test.
I have two problems:
1- Winzip does not recognize the zip file while unix unzip does - Not sure if this is due to #2 below
2- when I use unzip to unzip the file, it unzips the whole directory hierarchy: It creates /var/tmp/test inside of /var/tmp/test leading to /var/tmp/test/var/tmp/test and then the files inside that... I only want to zip the files and not the hierarchy...
Any help would be much appreciated!
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipFiles {
List<String> fileList;
String OUTPUT_ZIP_FILE;
String SOURCE_FOLDER;
ZipFiles() {
fileList = new ArrayList<String>();
}
public void zipIt(String ZipFiles) {
byte[] buffer = new byte[1024];
String source = "";
Boolean shouldZip = true;
try {
try {
// System.out.println("ZipFiles::zipIt::SOURCE_FOLDER::" +
// SOURCE_FOLDER);
source = SOURCE_FOLDER.substring(
SOURCE_FOLDER.lastIndexOf("\\") + 1,
SOURCE_FOLDER.length());
// System.out.println("ZipFiles::zipIt::source::" + source);
} catch (Exception e) {
source = SOURCE_FOLDER;
}
for (String file : this.fileList) {
if (file.endsWith("zip")) // This has already been zipped
{
shouldZip = false;
}
}
if (shouldZip) {
FileOutputStream fos = new FileOutputStream(ZipFiles);
ZipOutputStream zos = new ZipOutputStream(fos);
// System.out.println("Output to Zip : " + ZipFiles);
for (String file : this.fileList) {
// System.out.println("File Added : " + file);
ZipEntry ze = new ZipEntry(source + File.separator + file);
zos.putNextEntry(ze);
FileInputStream in = new FileInputStream(SOURCE_FOLDER
+ File.separator + file);
int len;
while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
in.close();
}
zos.closeEntry();
// remember close it
zos.close();
}
// System.out.println("Folder successfully compressed");
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void generateFileList(File node) {
// add file only
if (node.isFile()) {
fileList.add(generateZipEntry(node.toString()));
}
if (node.isDirectory()) {
String[] subNote = node.list();
for (String filename : subNote) {
generateFileList(new File(node, filename));
}
}
}
private String generateZipEntry(String file) {
// System.out.println("ZipFiles::generateZipEntry::file::" + file);
return file.substring(SOURCE_FOLDER.length(), file.length());
}
}
As noted in the update to my question, for issue #2: just replaced ZipEntry ze = new ZipEntry(source + File.separator + file); with ZipEntry ze = new ZipEntry(file);
For issue #1 with winzip, the zip file I was testing was actually being downloaded via my webapp. Problem was in my groovy side of the code actually:
def download = {
def folder = params.folder
def file = new File( folder.toString())
response.setHeader "Content-disposition", "attachment; filename=${file.name}"
response.outputStream << file.text
response.outputStream.flush()
response.outputStream.close()
}
When I replaced outputStream <<file.text with outputStream << file.newInputStream() everything worked correctly.
As for Unix' unzip, I was testing directly on the created file instead of the downloaded file!!!
I am facing an unusal issue.I am building a tool which is scheduled to run every 5 mins.
It will pick up the zip files from a particular directory and extract files (depending on the file name) to a destination. I am using zipentry to get each filename in zip file and then extracting as required then I back them (zip files, once I finish all the files in a zip) to a particular directory and then delete the zip file. But sometimes (not always) the zip files do not get deleted. Since I am using fileutils.forcedelete(). I am getting an exception: unable to delete file. So I changed to the code to using fileutils.forcedeleteonexit() still some files remain in the source.
Here is a sample of my code:
sourceFile=new file(zipfile);
zipFile = new ZipFile(sourceFile);
zEnum = (Enumeration<ZipEntry>) zipFile.entries();
for (int a = 0; a < zipFile.size(); a++)
{
ZipEntry zE = zEnum.nextElement();
//Function uses zip4j for extracting. No streams used.
extract(String sourceZipFile, String fileNameToExtract, String outputFolder);
}
//I tried it with finally either
zipFile.close();
//Using fileutils to copy. No streams used.
copyFile(sourceFile, backup);
FileUtils.forceDeleteOnExit(sourceFile);
There are no streams used but I am getting a lock on files sometimes (not always).
What seems to be the bug here? Is it the zip4j extraction that is causing the problem or anything else? I am using zip4j 1.3.1.
I think your problem related with OS file buffers, that sometimes are not flushed when you are trying to delete file.
Did you try to use sourceFile.deleteOnExit() instead FileUtils.forceDeleteOnExit(sourceFile)?
Also you can try to check sourceFile.canWrite before deleting (may be it may helps)
You can also try to use FileInputStream() before deleting:
FileInputStream fi = new FileInputStream(sourceFile);
fi.getFD().sync();
Use apache-commons IO's FileDeleteStrategy. Something like:
FileDeleteStrategy.FORCE.delete(file);
Update:
It should be the way IO is being handled in your application. I have written simple code which copies a zip file to a temporary zip, deflates the temporary zip and after few seconds deletes it. Here you go:
public class ZipTest {
private static String dirPath = "/home/ubuntuuser/Desktop/";
public static void main(String[] args) throws Exception {
File myzip = new File(dirPath + "content.zip");
String tempFileStr = dirPath + "content_temp.zip";
File tempFile = new File(tempFileStr);
String unzipFolderStr = dirPath + "unzip";
copyUsingChannels(myzip, tempFile);
// copyUsingStreams(myzip, tempFile);
unZip(tempFileStr, unzipFolderStr);
Thread.sleep(3000);
tempFile.delete();
}
private static void copyUsingStreams(File myzip, File tempFile)
throws IOException, FileNotFoundException {
byte[] barray = new byte[1024];
if (!tempFile.exists())
{
tempFile.createNewFile();
}
FileOutputStream fos = new FileOutputStream(tempFile);
FileInputStream fis = new FileInputStream(myzip);
int length = 0;
while ((length = fis.read(barray)) != -1)
{
fos.write(barray, 0, length);
}
fis.close();
fos.close();
}
public static void copyUsingChannels(final File srcFile, final File destFile) throws Exception
{
if (!destFile.exists())
{
destFile.createNewFile();
}
FileChannel source = new FileInputStream(srcFile).getChannel();
FileChannel destination = new FileOutputStream(destFile).getChannel();
source.transferTo(0, source.size(), destination);
source.close();
destination.close();
}
private static void unZip(String zipFile, String outputFolder) throws Exception {
byte[] buffer = new byte[1024];
File folder = new File(outputFolder);
if (!folder.exists()) {
folder.mkdir();
}
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
ZipEntry ze = zis.getNextEntry();
while (ze != null) {
String fileName = ze.getName();
File newFile = new File(outputFolder + File.separator + fileName);
System.out.println("file unzip : " + newFile.getAbsoluteFile());
new File(newFile.getParent()).mkdirs();
if (ze.isDirectory())
{
newFile.mkdir();
ze = zis.getNextEntry();
continue;
}
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
ze = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
}
}
here i'm trying to zip only .txt file in a folder using java.
My code here was found with google and works perfectly but only for a specified .txt file.
Thank you.
import java.util.*;
import java.util.zip.*;
import java.io.*;
public class ZipFile
{
public static void main(String[] args) {
ZipOutputStream out = null;
InputStream in = null;
try {
File inputFile1 = new File("c:\\Target\\target.txt");// here i want to say only the directroy where .txt files are stored
File outputFile = new File("c:\\Target\\Archive_target.zip");//here i want to put zipped file in a different directory
OutputStream rawOut = new BufferedOutputStream(new FileOutputStream(outputFile));
out = new ZipOutputStream(rawOut);
InputStream rawIn = new FileInputStream(inputFile1);
in = new BufferedInputStream(rawIn);
ZipEntry entry = new ZipEntry("c:\\Target\\target.txt");
out.putNextEntry(entry);
byte[] buf = new byte[2048];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
catch(IOException e) {
e.printStackTrace();
}
finally {
try {
if(in != null) {
in.close();
}
if(out != null) {
out.close();
}
}
catch(IOException ignored)
{ }
}
}
}
You need to use File.list(...) to get a list of all the text files in the folder. Then you create a loop to write each file to the zip file.
I just add these lines just after
"File outputFile = new File("c:\Target\Archive_target.zip");
from my previous code.
code added:
File Dir = new File("c:/Target");
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return !name.startsWith(".txt");
}
};
String[] children = Dir.list(filter);
You can get a list of all text files in your directory by using the following method of the File class:
String[] list(FilenameFilter filter)
Create a File object that points to your DIRECTORY (I know it sounds illogical, but that's the way it is- you can test if it is a directory using isDirectory()) and then use the FilenameFilter to say, for example, accept this file if its name contain ".txt"
Create a FilenameFilter that accepts only *.txt file , and then just use
list = File.list(yourNameFilter);
and then just add all the files in the list to the zip file
For example, I want to zip a file stored in /Users/me/Desktop/image.jpg
I made this method:
public static Boolean generateZipFile(ArrayList<String> sourcesFilenames, String destinationDir, String zipFilename){
// Create a buffer for reading the files
byte[] buf = new byte[1024];
try {
// VER SI HAY QUE CREAR EL ROOT PATH
boolean result = (new File(destinationDir)).mkdirs();
String zipFullFilename = destinationDir + "/" + zipFilename ;
System.out.println(result);
// Create the ZIP file
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFullFilename));
// Compress the files
for (String filename: sourcesFilenames) {
FileInputStream in = new FileInputStream(filename);
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(filename));
// 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();
return true;
} catch (IOException e) {
return false;
}
}
But when I extract the file, the unzipped files have the full path.
I don't want the full path of each file in the zip i only want the filename.
How can I made this?
Here:
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(filename));
You're creating the entry for that file using the whole path. If you just use the name ( without the path ) you'll have what you need:
// Add ZIP entry to output stream.
File file = new File(filename); //"Users/you/image.jpg"
out.putNextEntry(new ZipEntry(file.getName())); //"image.jpg"
You're finding your source data using the relative path to the file, then setting the Entry to the same thing. Instead you should turn the source into a File object, and then use
putNextEntry(new ZipEntry(sourceFile.getName()))
that'll give you just the final part of the path (ie, the actual file name)
Do as Jason said, or if you want to keep your method signature, do it like this:
out.putNextEntry(new ZipEntry(new File(filename).getName()));
or, using FileNameUtils.getName from apache commons/io:
out.putNextEntry(new ZipEntry(FileNameUtils.getName(filename)));
You could probably get away with accessing source files via new FileInputStream(new File(sourceFilePath, sourceFileName)).
// easy way of zip a file
import java.io.*;
import java.util.zip.*;
public class ZipCreateExample{
public static void main(String[] args) throws Exception {
// input file
FileInputStream in = new FileInputStream("F:/ZipCreateExample.txt");;
// out put file
ZipOutputStream out =new ZipOutputStream(new FileOutputStrea("F:/tmp.zip"));
// name of file in zip folder
out.putNextEntry(new ZipEntry("zippedfile.txt"));
byte[] b = new byte[1024];
int count;
// writing files to new zippedtxt file
while ((count = in.read(b)) > 0) {
System.out.println();
out.write(b, 0, count);
}
out.close();
in.close();
}
}
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.jpg") || sourceFiles[i].equalsIgnoreCase("file1.jpg")) {
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);
}
If you zip two files of the same name but with different paths you will run into duplicate file entry errors, though.