0

I found this ZipUtils class on this post: how to zip a folder itself using java

I modified it so I could pass a zip file name. However, the only way it works is with a hardcoded static string. The zippedFile string is grabbed from the database. I have compared the dbZippedFile and hardcodedZippedFile and they are both identical... Perhaps there is an issue with using a non-static string with FileOutputStream? This problem only occurs when trying to zip directories (one file works fine). Does anyone know what I am doing wrong or have a good alternative?

It never throws an error. It just fails to create the file. In the code snippet, if you replace zippedFile.getPath() with the hardcoded string representation (i.e. "D:\\dir\\file.zip") it works.

Code:

 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
 Date date = new Date();

 String zipName = name+ "_" + dateFormat.format(date) + ".zip";
 zippedFile = new File(archive, zipName);
 if (zippedFile .exists()) {
      zippedFile .delete();
 }
 ZipUtils.main(dirToZip.getPath(), zippedFile.getPath());

Class:

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 ZipUtils
{

private List<String> fileList;
private static String SOURCE_FOLDER; // SourceFolder path

public ZipUtils()
{
 fileList = new ArrayList<String>();

}

public static void main(String source, String output)
{       
 SOURCE_FOLDER = source;

 //output = "D:\\dir\\file.zip";
 ZipUtils appZip = new ZipUtils();
 appZip.generateFileList(new File(SOURCE_FOLDER));
 appZip.zipIt(output);
}

public void zipIt(String zipFile)
{
 byte[] buffer = new byte[1024];
 String source = "";
 FileOutputStream fos = null;
 ZipOutputStream zos = null;

 try
 {
    try
    {
       source = SOURCE_FOLDER.substring(SOURCE_FOLDER.lastIndexOf("\\") + 1, SOURCE_FOLDER.length());
    }
   catch (Exception e)
   {
      source = SOURCE_FOLDER;
   }
   fos = new FileOutputStream(zipFile);
   zos = new ZipOutputStream(fos);

   System.out.println("Output to Zip : " + zipFile);
   FileInputStream in = null;

   for (String file : this.fileList)
   {
      System.out.println("File Added : " + file);
      ZipEntry ze = new ZipEntry(source + File.separator + file);

      zos.putNextEntry(ze);
      try
      {
         in = new FileInputStream(SOURCE_FOLDER + File.separator + file);
         int len;
         while ((len = in.read(buffer)) > 0)
         {
            zos.write(buffer, 0, len);
         }
      }
      finally
      {
         in.close();
      }
   }

   zos.closeEntry();
   System.out.println("Folder successfully compressed");

}
catch (IOException ex)
{
   ex.printStackTrace();
}
finally
{
   try
   {
      zos.close();
   }
   catch (IOException e)
   {
      e.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)
{
 return file.substring(SOURCE_FOLDER.length() + 1, file.length());
}
}    
Community
  • 1
  • 1
  • Huh, that sounds like a strange problem. Modifications to Strings in Java don't really happen (all String operations return a new String) so I don't see how that'd make a difference. Can you please post code that is causing an error and what the error is? – k_g Feb 26 '15 at 00:05
  • 3
    Show examples that doesn't work, and what you expected. – Thorbjørn Ravn Andersen Feb 26 '15 at 00:06
  • 1
    Pass the source file reference to the `ZipUtils` class in some way – MadProgrammer Feb 26 '15 at 00:09
  • I added a code snippet and further explanation. –  Feb 26 '15 at 00:14
  • in your updated question, it seems you are confusing the source directory to compress, with the output zipfile – guido Feb 26 '15 at 00:16

1 Answers1

1

There are probably hundreds of ways you could fix this depending on your needs, but from my perspective, what you want to be able to do is say "Zip this folder to this zip file" in as few lines of code as possible...

To this end, I could alter the code to allow you to do something like...

ZipUtils appZip = new ZipUtils();
appZip.zipIt(new File(source), new File(output));

The use of File leaves no ambiguity as to the meaning of the parameters. This mechanism also means that you can call zipIt again and again and again based on your needs, without having to create a new instance of ZipUtils

This will require some modification to the base code, as it assumes String values for the file paths, which frankly is just maddening, as all the information you really want can be more easily obtained from the File object - IMHO. This also means that you don't need to maintain a reference to the source path at all, beyond the scope of the zipIt method

public static class ZipUtils {

    private final List<File> fileList;

    private List<String> paths;

    public ZipUtils() {
        fileList = new ArrayList<>();
        paths = new ArrayList<>(25);
    }

    public void zipIt(File sourceFile, File zipFile) {
        if (sourceFile.isDirectory()) {
            byte[] buffer = new byte[1024];
            FileOutputStream fos = null;
            ZipOutputStream zos = null;

            try {

                String sourcePath = sourceFile.getPath();
                generateFileList(sourceFile);

                fos = new FileOutputStream(zipFile);
                zos = new ZipOutputStream(fos);

                System.out.println("Output to Zip : " + zipFile);
                FileInputStream in = null;

                for (File file : this.fileList) {
                    String path = file.getParent().trim();
                    path = path.substring(sourcePath.length());

                    if (path.startsWith(File.separator)) {
                        path = path.substring(1);
                    }

                    if (path.length() > 0) {
                        if (!paths.contains(path)) {
                            paths.add(path);
                            ZipEntry ze = new ZipEntry(path + "/");
                            zos.putNextEntry(ze);
                            zos.closeEntry();
                        }
                        path += "/";
                    }

                    String entryName = path + file.getName();
                    System.out.println("File Added : " + entryName);
                    ZipEntry ze = new ZipEntry(entryName);

                    zos.putNextEntry(ze);
                    try {
                        in = new FileInputStream(file);
                        int len;
                        while ((len = in.read(buffer)) > 0) {
                            zos.write(buffer, 0, len);
                        }
                    } finally {
                        in.close();
                    }
                }

                zos.closeEntry();
                System.out.println("Folder successfully compressed");

            } catch (IOException ex) {
                ex.printStackTrace();
            } finally {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    protected void generateFileList(File node) {

        // add file only
        if (node.isFile()) {
            fileList.add(node);

        }

        if (node.isDirectory()) {
            File[] subNote = node.listFiles();
            for (File filename : subNote) {
                generateFileList(filename);
            }
        }
    }
}

ps- You public static void main, isn't a valid "main entry point", it should be public static void main(String[] args) ;)

So, based on your code snippet, you could simply do something like...

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
Date date = new Date();

String zipName = name+ "_" + dateFormat.format(date) + ".zip";
zippedFile = new File(archive, zipName);
if (zippedFile exists()) {
    zippedFile.delete();
}

ZipUtils zu = new ZipUtils();
zu.zipIt(dirToZip, zippedFile);
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • This is definitely a better implementation. However, it did not solve my original problem. zu.zipIt(new File(source), new File(output)) does not create a zip file. However, zuzipIt(new File(source), new File("D:\\dir\\file.zip")) does. Even though output == "D:\\dir\\file.zip". –  Feb 26 '15 at 00:31
  • That doesn't make sense, both are `String` values. What does `output` equal? – MadProgrammer Feb 26 '15 at 00:34
  • I know! output == "D:\\dir\\file.zip". Now if I set output = "D:\\dir\\file.zip". Then run zu.zipIt(new File(source), new File(output)). It works. However if output is modified in anyway, it no longer works. –  Feb 26 '15 at 00:38
  • *"However if output is modified in anyway, it no longer works"* What do you mean by "modified"? – MadProgrammer Feb 26 '15 at 00:40
  • Poor wording. zippedFile = new File(archive, zipName) creates the file by concatenating the strings archive and zipName, which were grabbed from the database. zippedFile (aka output) was created after the code was compiled. If zippedFile = "D:\\dir\\file.zip", is hardcoded then it creates the file. Something like output = String.join("/", zippedFile.split("\\\\")) will also work just fine. –  Feb 26 '15 at 00:54
  • The it sounds more like the problem is without the values that are used to generate the `zippedFile`, as clearly, if you pass the utility class valid values, it works... – MadProgrammer Feb 26 '15 at 00:57
  • The values are valid. I have printed them to console and copied and pasted them into the code and it works fine. I've also done dbOut.equals(hardcodeOut) and dbOut.compareTo(hardcodeOut). They are identical. –  Feb 26 '15 at 01:00
  • 1
    If, there was something wrong with the `ZipUtil`, then neither would work. Without more information about the values you are using, I'm not sure how you expect me to debug the issue for you :P. The issue isn't with the utility, it's with the values are you passing, directly or indirectly (ie, the path doesn't exist, the file is locked or you don't have permissions to write to the location)... – MadProgrammer Feb 26 '15 at 01:04