commons-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stephen Huey <stephen.h...@gmail.com>
Subject Windows XP Compressed Folders doesn't recognize my VFS-based zip file
Date Tue, 15 Dec 2009 07:54:24 GMT
I'm using GaeVFS which is based on Commons VFS, and I feel that my question
is probably more relevant to Commons VFS than the Google App Engine layer on
top of it.  My goal is to construct valid zip files on Google App Engine,
and I successfully used GaeVFS to create zip files that Mac OS X can open
and that Winzip on Windows can open, but Windows XP Compressed Folders
refused to acknowledge files in subdirectories in the zip until I removed
the leading forward slash from a ZipEntry whose name began with a
directory.

For example, the following basic class successfully generates a zip file
containing a file in a subdirectory that Windows XP Compressed Folders will
open:


import java.util.zip.*;
import java.io.*;
public class ZipThis {
  public static void main(String args[]) throws IOException {
    if (args.length < 1) {
      System.err.println("usage: java ZipThis Zip.zip");
      System.exit(-1);
    }
    File zipFile = new File(args[0]);
    if (zipFile.exists()) {
      System.err.println("Zip file already exists, please try another");
      System.exit(-2);
    }
    FileOutputStream fos = new FileOutputStream(zipFile);
    ZipOutputStream zos = new ZipOutputStream(fos);
    int bytesRead;
    String[] files = new String[] {"D:/stylessub/styles.xml",
"D:/document.xml"};
    String[] entryName = new String[] {"stylessub/styles.xml",
"document.xml"};
    byte[] buffer = new byte[1024];
    for (int i=0, n=files.length; i < n; i++) {
      String name = files[i];
      File file = new File(name);
      if (!file.exists()) {
        System.out.println("Skipping: " + name);
        continue;
      }
      BufferedInputStream bis = new BufferedInputStream(new
FileInputStream(file));
      ZipEntry entry = new ZipEntry(entryName[i]);
      zos.putNextEntry(entry);
      while ((bytesRead = bis.read(buffer)) != -1) {
        zos.write(buffer, 0, bytesRead);
      }
      bis.close();
      zos.closeEntry();

    }
    zos.close();
  }
}


Now I'm trying to get my virtual file system code to generate a zip that
Windows won't complain about with this error message:  "The Compressed
(zipped) Folder is isvalid or corrupted."  I want to meet the Microsoft
employee who wrote that error message!  :)

So here's some initial setup in my servlet:

FileObject docxZipFile = FileObjectHelper.createFile(fsManager,
"gae://gaevfs/generatedZip/docxFile.zip");
FileObject docxRootFolder = FileObjectHelper.createFolder(fsManager,
"gae://gaevfs/docxDirectory");

These helper methods are being used:

    public static FileObject createFile(FileSystemManager fsManager, String
absolutePath) throws FileSystemException {
        FileObject theFile = fsManager.resolveFile( absolutePath );
        if ( theFile.exists() == false) {
            theFile.createFile();
        }
        return theFile;
    }

    public static FileObject createFolder(FileSystemManager fsManager,
String absolutePath) throws FileSystemException {
        FileObject theFolder = fsManager.resolveFile( absolutePath );
        if ( theFolder.exists() == false) {
            theFolder.createFolder();
        }
        return theFolder;
    }

Pardon the near redundancy.  Anyway, the next line begins the zipping:

FileObjectHelper.zipDir(docxZipFile, docxRootFolder);


Here's the zipDir method:


    public static void zipDir(FileObject docxZipFile, FileObject
directoryToZip) throws Exception {
        OutputStream out = docxZipFile.getContent().getOutputStream();
        //ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ZipOutputStream zout = new ZipOutputStream(out);
        addDir(directoryToZip, zout, directoryToZip.getName().getBaseName()
+ "/");
        out.close();
        //return bos.toByteArray();
    }


As you can see, I played with pushing down a byte array of the resulting zip
file on the servlet output stream instead of saving the generated zip file
to the virtual file system, but that didn't make my error message go away.
Here's the addDir method:


    public static void addDir(FileObject dirObj, ZipOutputStream out, String
basePathSoFar) throws IOException {
        System.out.println("addDir for " + dirObj.getName());
        FileObject[] files = dirObj.getChildren();
        byte[] tmpBuf = new byte[1024];

        for (int i = 0; i < files.length; i++) {
            FileObject currentFile = files[i];
            System.out.println("currentFile is " +
currentFile.getName().getBaseName());
            if (currentFile.getType().equals(FileType.FOLDER)) {
                addDir(currentFile, out, basePathSoFar +
currentFile.getName().getBaseName() + "/");

            } else {

                System.out.println("making entry for: " + basePathSoFar +
currentFile.getName().getBaseName());
                InputStream in = currentFile.getContent().getInputStream();
                out.putNextEntry(new ZipEntry(basePathSoFar +
currentFile.getName().getBaseName()));
                int len;
                while ((len = in.read(tmpBuf)) != -1) {
                    out.write(tmpBuf, 0, len);
                }
                out.closeEntry();
                in.close();
            }
        } // end for loop
    }


I used to have the buffer read check for greater than zero rather than not
equal to negative one.  Anyway, for some reason this doesn't work even
though it seems very close to the working program above.  I'll paste the
print statements down below so you can see that it doesn't appear as if VFS
is putting any extra junk into the ZipEntry names or anything like that.

I'd love to try out any bright ideas anyone has!

Thanks so much...



The server is running at http://localhost:8888/
Passing the zip file:
/D:/workspace/my-app/war/gaevfs/generatedZip/docxFile.zip
Writing this zip file: docxFile.zip
Zipping up  directory: docxDirectory
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory
currentFile is _rels
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/_rels
currentFile is docProps
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/docProps
currentFile is app.xml
making entry for: docxDirectory/docProps/app.xml
currentFile is core.xml
making entry for: docxDirectory/docProps/core.xml
currentFile is word
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/word
currentFile is document.xml
making entry for: docxDirectory/word/document.xml
currentFile is fontTable.xml
making entry for: docxDirectory/word/fontTable.xml
currentFile is settings.xml
making entry for: docxDirectory/word/settings.xml
currentFile is styles.xml
making entry for: docxDirectory/word/styles.xml
currentFile is webSettings.xml
making entry for: docxDirectory/word/webSettings.xml
currentFile is _rels
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/word/_rels
currentFile is document.xml.rels
making entry for: docxDirectory/word/_rels/document.xml.rels
currentFile is media
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/word/media
currentFile is image1.jpeg
making entry for: docxDirectory/word/media/image1.jpeg
currentFile is image2.jpeg
making entry for: docxDirectory/word/media/image2.jpeg
currentFile is theme
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/word/theme
currentFile is theme1.xml
making entry for: docxDirectory/word/theme/theme1.xml
currentFile is [Content_Types].xml
making entry for: docxDirectory/[Content_Types].xml
Passing the zip file:
/D:/workspace/my-app/war/gaevfs/generatedZip/betterzip.zip
Writing this zip file: betterzip.zip
Zipping up  directory: docxDirectory
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory
currentFile is _rels
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/_rels
currentFile is docProps
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/docProps
currentFile is app.xml
making entry for: docxDirectory/docProps/app.xml
currentFile is core.xml
making entry for: docxDirectory/docProps/core.xml
currentFile is word
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/word
currentFile is document.xml
making entry for: docxDirectory/word/document.xml
currentFile is fontTable.xml
making entry for: docxDirectory/word/fontTable.xml
currentFile is settings.xml
making entry for: docxDirectory/word/settings.xml
currentFile is styles.xml
making entry for: docxDirectory/word/styles.xml
currentFile is webSettings.xml
making entry for: docxDirectory/word/webSettings.xml
currentFile is _rels
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/word/_rels
currentFile is document.xml.rels
making entry for: docxDirectory/word/_rels/document.xml.rels
currentFile is media
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/word/media
currentFile is image1.jpeg
making entry for: docxDirectory/word/media/image1.jpeg
currentFile is image2.jpeg
making entry for: docxDirectory/word/media/image2.jpeg
currentFile is theme
addDir for gae:///D:/workspace/my-app/war/gaevfs/docxDirectory/word/theme
currentFile is theme1.xml
making entry for: docxDirectory/word/theme/theme1.xml
currentFile is [Content_Types].xml
making entry for: docxDirectory/[Content_Types].xml

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message