-
Bug
-
Resolution: Not an Issue
-
P4
-
None
-
8u40
-
x86_64
-
windows_7
FULL PRODUCT VERSION :
>java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
>ver
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Using java.util.zip to create zip files and then later reread them, the scanned ZipEntry's show uncompressed size of -1.
But although it cannot read its own sizes:
- other zip processers can correctly read the sizes from those same files (tested with Info-zip unzip, and Python zipfile library).
- java.util.zip does show valid sizes when scanning zip files created by an external zipper (Info-zip zip)
The only case that fails is java.util.zip reading zip files created by itself.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Commands shown are Windows 7 command prompt
Copy the enclosed Java source file (ZipArchive.java) into a directory.
Also in that directory create a subdirectory "root" and create a file in
it so we have something to zip. (the file I used happened to be
TestAbbrevValue.java, which you will see in the outputs below.)
Run the following commands in the directory containing ZipArchive.java.
Compile the java program:
del *.class & javac *.java
Create a zip file with the resulting Java tool:
java ZipArchive zip java.zip root
List the java-created zip file's entries using the Java tool (FAILS):
java ZipArchiver list java.zip
LIST
Length Time Name
---------- ---------------------------- ----
-1 Tue Sep 01 18:48:26 PDT 2009 TestAbbrevValue.java
List the java-created zip file's entries using unzip (succeeds):
unzip -l java.zip
Archive: java.zip
Length Date Time Name
--------- ---------- ----- ----
419 09/01/2009 18:48 TestAbbrevValue.java
--------- -------
419 1 file
Create a reference zip file using Info-zip zip:
del zip.zip 2>nul & cd root & zip -9 -r ../zip.zip . & cd ..
List the zip-created zip file's entries using the Java tool (succeeds):
java ZipArchiver list zip.zip
LIST
Length Time Name
---------- ---------------------------- ----
419 Tue Sep 01 18:48:26 PDT 2009 TestAbbrevValue.java
List the zip-created zip file's entries using unzip (succeeds):
unzip -l zip.zip
Archive: zip.zip
Length Date Time Name
--------- ---------- ----- ----
419 09/01/2009 18:48 TestAbbrevValue.java
--------- -------
419 1 file
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The command
java ZipArchiver list java.zip
from the steps to reproduce should yield a correct size.
ACTUAL -
Size yielded is -1.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.*;
import java.util.zip.*;
/** Uses java.util.zip. */
class ZipArchiver {
private static final int BUFFER_SIZE = 4096;
/** Extracts from archive "archivePath" to directory "rootPath". */
public void extract(Path archivePath, Path rootPath) throws IOException {
ZipInputStream zipIn = null;
try {
zipIn = new ZipInputStream(new BufferedInputStream(
Files.newInputStream(archivePath)));
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
try {
String fileName = entry.getName();
Path targetFile = rootPath.resolve(fileName);
long time = entry.getTime();
if (fileName.endsWith("/")) {
Files.createDirectories(targetFile);
} else {
// Extract file.
Files.createDirectories(targetFile.getParent());
try (OutputStream out =
Files.newOutputStream(targetFile)) {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = zipIn.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
} catch (IOException ex) {
System.out.println("*** IO ERROR" +
" EXTRACTING BINARY FILE: " +
ex.getClass().getName());
System.out.println(" " + ex.getMessage());
}
Files.setLastModifiedTime(targetFile,
FileTime.fromMillis(time));
}
} catch (Exception ex) {
System.out.println("Could not extract file " +
entry.getName() + ": " + ex);
} finally {
zipIn.closeEntry();
}
}
} catch (NoSuchFileException e) {
// No ZIP file, no files extracted, not an error.
} finally {
if (zipIn != null)
zipIn.close();
}
}
/** Writes a new archive "archivePath" from the contents of
directory "rootPath". */
public void write(Path archivePath, Path rootPath) throws IOException {
try (ZipOutputStream zipOut = new ZipOutputStream(
Files.newOutputStream(archivePath))) {
zipOut.setLevel(9);
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
Path relFile = rootPath.relativize(file);
String fileName = file.toString();
// Convert name to Zip format.
String zipName = relFile.toString().replace(
File.separatorChar, '/');
if (zipName.startsWith("./"))
zipName = zipName.substring(2);
ZipEntry entry = new ZipEntry(zipName);
entry.setTime(Files.getLastModifiedTime(file).toMillis());
//entry.setSize(Files.size(file)); // not necessary
zipOut.putNextEntry(entry);
// Store file.
InputStream in = Files.newInputStream(file);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
zipOut.write(buffer, 0, bytesRead);
}
in.close();
zipOut.flush();
zipOut.closeEntry();
return FileVisitResult.CONTINUE;
}
});
}
}
/** Lists entries from archive "archivePath". */
public List<Entry> entries(Path archivePath) throws IOException {
List<Entry> entries = new ArrayList<>();
ZipInputStream zipIn = null;
try {
zipIn = new ZipInputStream(new BufferedInputStream(
Files.newInputStream(archivePath)));
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
try {
entries.add(new Entry(entry.getName(),
entry.getSize(), entry.getTime()));
} catch (Exception ex) {
System.out.println("Error getting zip entry " + ex);
} finally {
zipIn.closeEntry();
}
zipIn.closeEntry();
}
} catch (NoSuchFileException e) {
// No ZIP file, no files extracted, not an error.
} finally {
if (zipIn != null)
zipIn.close();
}
return entries;
}
public static class Entry {
public final String name;
public final long size;
public final long mtime;
public Entry(String name, long size, long mtime) {
this.name = name;
this.size = size;
this.mtime = mtime;
}
@Override
public String toString() {
return "Entry(name: " + name +
", size: " + size +
", mtime: " + new Date(mtime) +
")";
}
}
/** Tool to exercise functionality. */
public static void main(String[] args) throws IOException {
int argsLen = args.length;
if (argsLen < 1)
usage();
ZipArchiver archiver = new ZipArchiver();
switch (args[0]) {
case "zip":
if (argsLen != 3)
usage();
System.out.println("ZIP");
archiver.write(Paths.get(args[1]), Paths.get(args[2]));
break;
case "unzip":
if (argsLen != 3)
usage();
System.out.println("UNZIP");
archiver.extract(Paths.get(args[1]), Paths.get(args[2]));
break;
case "list":
if (argsLen != 2)
usage();
System.out.println("LIST");
System.out.println(" Length Time Name");
System.out.println("---------- ---------------------------- ----");
for (Entry entry : archiver.entries(Paths.get(args[1]))) {
System.out.printf("%10s %s %s%n",
entry.size, new Date(entry.mtime), entry.name);
}
break;
default:
System.err.println("Unknown command: " + args[0]);
System.exit(2);
break;
}
}
private static void usage() {
System.err.println("Args: zip|unzip zip-file dir");
System.err.println(" list zip-file");
System.exit(2);
}
}
---------- END SOURCE ----------
>java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
>ver
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Using java.util.zip to create zip files and then later reread them, the scanned ZipEntry's show uncompressed size of -1.
But although it cannot read its own sizes:
- other zip processers can correctly read the sizes from those same files (tested with Info-zip unzip, and Python zipfile library).
- java.util.zip does show valid sizes when scanning zip files created by an external zipper (Info-zip zip)
The only case that fails is java.util.zip reading zip files created by itself.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Commands shown are Windows 7 command prompt
Copy the enclosed Java source file (ZipArchive.java) into a directory.
Also in that directory create a subdirectory "root" and create a file in
it so we have something to zip. (the file I used happened to be
TestAbbrevValue.java, which you will see in the outputs below.)
Run the following commands in the directory containing ZipArchive.java.
Compile the java program:
del *.class & javac *.java
Create a zip file with the resulting Java tool:
java ZipArchive zip java.zip root
List the java-created zip file's entries using the Java tool (FAILS):
java ZipArchiver list java.zip
LIST
Length Time Name
---------- ---------------------------- ----
-1 Tue Sep 01 18:48:26 PDT 2009 TestAbbrevValue.java
List the java-created zip file's entries using unzip (succeeds):
unzip -l java.zip
Archive: java.zip
Length Date Time Name
--------- ---------- ----- ----
419 09/01/2009 18:48 TestAbbrevValue.java
--------- -------
419 1 file
Create a reference zip file using Info-zip zip:
del zip.zip 2>nul & cd root & zip -9 -r ../zip.zip . & cd ..
List the zip-created zip file's entries using the Java tool (succeeds):
java ZipArchiver list zip.zip
LIST
Length Time Name
---------- ---------------------------- ----
419 Tue Sep 01 18:48:26 PDT 2009 TestAbbrevValue.java
List the zip-created zip file's entries using unzip (succeeds):
unzip -l zip.zip
Archive: zip.zip
Length Date Time Name
--------- ---------- ----- ----
419 09/01/2009 18:48 TestAbbrevValue.java
--------- -------
419 1 file
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The command
java ZipArchiver list java.zip
from the steps to reproduce should yield a correct size.
ACTUAL -
Size yielded is -1.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.util.*;
import java.util.zip.*;
/** Uses java.util.zip. */
class ZipArchiver {
private static final int BUFFER_SIZE = 4096;
/** Extracts from archive "archivePath" to directory "rootPath". */
public void extract(Path archivePath, Path rootPath) throws IOException {
ZipInputStream zipIn = null;
try {
zipIn = new ZipInputStream(new BufferedInputStream(
Files.newInputStream(archivePath)));
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
try {
String fileName = entry.getName();
Path targetFile = rootPath.resolve(fileName);
long time = entry.getTime();
if (fileName.endsWith("/")) {
Files.createDirectories(targetFile);
} else {
// Extract file.
Files.createDirectories(targetFile.getParent());
try (OutputStream out =
Files.newOutputStream(targetFile)) {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = zipIn.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
} catch (IOException ex) {
System.out.println("*** IO ERROR" +
" EXTRACTING BINARY FILE: " +
ex.getClass().getName());
System.out.println(" " + ex.getMessage());
}
Files.setLastModifiedTime(targetFile,
FileTime.fromMillis(time));
}
} catch (Exception ex) {
System.out.println("Could not extract file " +
entry.getName() + ": " + ex);
} finally {
zipIn.closeEntry();
}
}
} catch (NoSuchFileException e) {
// No ZIP file, no files extracted, not an error.
} finally {
if (zipIn != null)
zipIn.close();
}
}
/** Writes a new archive "archivePath" from the contents of
directory "rootPath". */
public void write(Path archivePath, Path rootPath) throws IOException {
try (ZipOutputStream zipOut = new ZipOutputStream(
Files.newOutputStream(archivePath))) {
zipOut.setLevel(9);
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
Path relFile = rootPath.relativize(file);
String fileName = file.toString();
// Convert name to Zip format.
String zipName = relFile.toString().replace(
File.separatorChar, '/');
if (zipName.startsWith("./"))
zipName = zipName.substring(2);
ZipEntry entry = new ZipEntry(zipName);
entry.setTime(Files.getLastModifiedTime(file).toMillis());
//entry.setSize(Files.size(file)); // not necessary
zipOut.putNextEntry(entry);
// Store file.
InputStream in = Files.newInputStream(file);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
zipOut.write(buffer, 0, bytesRead);
}
in.close();
zipOut.flush();
zipOut.closeEntry();
return FileVisitResult.CONTINUE;
}
});
}
}
/** Lists entries from archive "archivePath". */
public List<Entry> entries(Path archivePath) throws IOException {
List<Entry> entries = new ArrayList<>();
ZipInputStream zipIn = null;
try {
zipIn = new ZipInputStream(new BufferedInputStream(
Files.newInputStream(archivePath)));
ZipEntry entry;
while ((entry = zipIn.getNextEntry()) != null) {
try {
entries.add(new Entry(entry.getName(),
entry.getSize(), entry.getTime()));
} catch (Exception ex) {
System.out.println("Error getting zip entry " + ex);
} finally {
zipIn.closeEntry();
}
zipIn.closeEntry();
}
} catch (NoSuchFileException e) {
// No ZIP file, no files extracted, not an error.
} finally {
if (zipIn != null)
zipIn.close();
}
return entries;
}
public static class Entry {
public final String name;
public final long size;
public final long mtime;
public Entry(String name, long size, long mtime) {
this.name = name;
this.size = size;
this.mtime = mtime;
}
@Override
public String toString() {
return "Entry(name: " + name +
", size: " + size +
", mtime: " + new Date(mtime) +
")";
}
}
/** Tool to exercise functionality. */
public static void main(String[] args) throws IOException {
int argsLen = args.length;
if (argsLen < 1)
usage();
ZipArchiver archiver = new ZipArchiver();
switch (args[0]) {
case "zip":
if (argsLen != 3)
usage();
System.out.println("ZIP");
archiver.write(Paths.get(args[1]), Paths.get(args[2]));
break;
case "unzip":
if (argsLen != 3)
usage();
System.out.println("UNZIP");
archiver.extract(Paths.get(args[1]), Paths.get(args[2]));
break;
case "list":
if (argsLen != 2)
usage();
System.out.println("LIST");
System.out.println(" Length Time Name");
System.out.println("---------- ---------------------------- ----");
for (Entry entry : archiver.entries(Paths.get(args[1]))) {
System.out.printf("%10s %s %s%n",
entry.size, new Date(entry.mtime), entry.name);
}
break;
default:
System.err.println("Unknown command: " + args[0]);
System.exit(2);
break;
}
}
private static void usage() {
System.err.println("Args: zip|unzip zip-file dir");
System.err.println(" list zip-file");
System.exit(2);
}
}
---------- END SOURCE ----------