我支持的ColdFusion应用程序安装在两个不同的位置。一个位置是使用ColdFusion 9和MS 2008运行Windows 2008,另一个是使用ColdFusion 11和MS 2012运行Windows 2012。应用程序提供了一个导出过程,使用CFZIP action = "zip",然后使用CFZIP action = "unzip"在目标机器上导入zip文件。
下面是生成用于导出的zip文件的代码:
<cfzip file="exportFileName.zip"
source="#exportDirectory#"
action="zip"
overwrite="yes"
recurse="yes">正确生成.zip文件,我可以在Windows和7Zip中打开它,没有任何问题。
下面是解压缩上面创建的zip文件的代码:
<cfzip action="unzip"
file="exportFileName.zip"
destination="#destination#\xml"
recurse ="yes"
storepath="yes">这是ColdFusion 9和ColdFusion 11实例的相同代码,但是当我们试图解压缩由ColdFusion 9实例上的ColdFusion 11实例生成的zip文件时,会收到以下错误:
确保该文件是有效的zip文件,并且是可访问的。原因: java.util.zip.ZipException:只有泄气项才能有EXT描述符
只有在使用CFZIP 9服务器上的ColdFusion 9服务器解压缩使用ColdFusion 11服务器上的CFZIP生成的压缩文件时,我们才会看到这个问题。我可以在ColdFusion 9服务器上提取从ColdFusion 11生成的zip文件的内容,使用7 Zip创建一个新的zip文件,该文件包含原始ColdFusion 11生成的zip文件的确切内容,而且我不会得到错误。
每当我们测试它从ColdFusion 11源到ColdFusion 11目的地或从ColdFusion 9源到ColdFusion 9目的地时,这个过程就会正常工作。当我们在ColdFusion 11上拉链,试图在ColdFusion 9上解压缩时,我们才会遇到这个问题。我已经搜索过谷歌,但似乎找不到像这样的问题。任何帮助都将不胜感激。
发布于 2015-11-20 10:26:14
TL/DR
CFZip on ColdFusion 11符合比PKZIP2.04g更晚的压缩规范ZipInputStream (似乎是CF9使用的)严格遵守了 2.04g (或更早版本)规范的。这两个版本之间一个微妙的区别是它们对零长度条目的处理(即子目录或mime类型等)。CFZip in CF11将这些条目标记为没有压缩的STORED (根据直觉和规范的后期版本,这很好,因为它们是零长度,所以压缩不会对它们造成任何影响),但是ZipInputStream (由CFZip在CF9中调用)希望使用DEFLATE方法将它们标记为压缩。
如果您没有零长度的条目,那么生成的文件是ColdFusion 可能会被读取(我认为它们会,但我不能确定地证明它)使用java的ZipInputStream;但是,如果您有零长度的文件,那么它就会抛出错误。
另一种办法是:
cfexecute在ColdFusion外部运行7zip或在ColdFusion中使用java org.apache.commons.compress库);或CFZip中使用CF11之外的其他内容,这将将它创建的压缩文件限制为以前的标准(参见下面)。详细答案:
来自压缩格式规范第4.4.4节的通用位标志:
位3:如果设置了此位,则本地标头中的字段crc-32、压缩大小和未压缩大小设置为零。在压缩数据之后,将正确的值放在数据描述符中。(注意:用于DOS的PKZIP版本2.04g只在方法8压缩时识别此位,更新版本的PKZIP对于任何压缩方法都识别此位。)
当本地文件头指示zip文件中有一个零长度条目(即一个目录或压缩文件中的某些其他东西,比如嵌入式mime类型)时,就会设置此位。
在PKZIP2.04g(或更早版本)标准下,它期望将压缩方法标志设置为DEFLATE (方法8压缩)。Java的ZipInputStream严格遵守的标准,如果找不到该压缩方法,则抛出一个ZipException (带有消息only DEFLATED entries can have EXT descriptor) (参见这里的源代码)。
当设置通用标志位时,cfzip似乎将压缩方法设置为STORED (方法0压缩-或不压缩)。据我所读,这符合PKZIP标准的后期版本,但与ZipInputStream类中Java实现的标准版本不向后兼容。
如何缓解这一问题:
CFZip中使用CFZip选项);或者CFZip中使用CF11,如果您希望使用严格的向后可压缩性,并且使用其他的东西(请参见下面的建议)。cfexecute调用外部程序来处理压缩文件;使用java org.apache.commons.compress库;等等)。如果您选择了选项2,并且希望使用与耳麦版本兼容的东西,那么这对我有效,我可以使用ZipInputStream解压缩文件(在CF9中直接测试,因为我没有CF9):
package zip;
import java.io.*;
import java.util.zip.*;
public class Zip {
private static void processFolder(
final File folder,
final ZipOutputStream zos,
final boolean recurse,
final int prefixLength,
final byte[] buffer
)
throws IOException
{
for ( final File file : folder.listFiles() )
{
if ( file.isFile() )
{
final String name = file.getPath().substring( prefixLength );
// System.out.println( name );
final ZipEntry entry = new ZipEntry( name );
zos.putNextEntry(entry);
try (FileInputStream is = new FileInputStream( file ) ){
int read;
while( (read = is.read( buffer ) ) != -1 )
{
zos.write( buffer, 0, read );
}
}
zos.closeEntry();
}
else if ( recurse && file.isDirectory() )
{
processFolder( file, zos, recurse, prefixLength, buffer );
}
}
}
public static void zipFolder(
final String folderPath,
final String outputName,
final boolean recurse,
final boolean overwrite
) throws IOException
{
final File folder = new File( folderPath );
if ( folder.exists() && folder.isDirectory() ) {
final File output = new File( outputName );
if ( overwrite || !output.exists() )
{
try ( ZipOutputStream zos = new ZipOutputStream( new FileOutputStream( output ) ) )
{
processFolder( folder, zos, recurse, folder.getPath().length() + 1, new byte[1024*4] );
}
}
}
}
}(注意:错误处理是最小的,所以如果要在生产环境中使用它,您可能希望使其更加健壮)。
如果编译该java类并将.class文件放在类路径上的zip子目录中(您可以将条目添加到ColdFusion管理面板中)。
然后您可以使用以下方法调用它:
<cfscript>
zip = CreateObject( "java", zip.Zip" );
zip.zipFolder(
"/path/to/folder/to/be/zipped/",
"/path/to/output/zip/file.zip",
true, // recurse
true // overwrite existing file
);
</cfscript>测试
如果您想要测试这种情况是如何发生的,那么这将在后面的规范下生成一个有效的zip文件,该文件将生成错误:
import java.io.*;
import java.util.zip.*;
public class TestZip {
public static void main( final String[] args ) throws IOException {
final File file = new File( args[0] );
if ( file.exists() )
{
System.out.println( "File already exists" );
return;
}
final boolean general_purpose_bit_flag_bit3_on = true;
final byte gpbf = general_purpose_bit_flag_bit3_on ? 0x08 : 0x00;
final byte[] contents = new byte[]{
// Local File header
'P', 'K', 3, 4, // Local File Header Signature
13, 0, // Version needed to extract
gpbf, 8, // General purpose bit flag
ZipEntry.STORED, 0, // Compression method
'q', 'l', 't', 'G', // Last Modification time & date
0, 0, 0, 0, // CRC32
0, 0, 0, 0, // Compressed Size
0, 0, 0, 0, // Uncompressed Size
12, 0, // File name length
0, 0, // Extra field length
'F', 'o', 'l', 'd', 'e', 'r', '_', 'n', 'a', 'm', 'e', '/',
// File name
// Central directory file header
'P', 'K', 1, 2, // Central Directory File Header Signature
13, 0, // Version made by
13, 0, // Version needed to extract
gpbf, 8, // General purpose bit flag
ZipEntry.STORED, 0, // Compression method
'q', 'l', 't', 'G', // Last Modification time & date
0, 0, 0, 0, // CRC32
0, 0, 0, 0, // Compressed Size
0, 0, 0, 0, // Uncompressed Size
12, 0, // File name length
0, 0, // Extra field length
0, 0, // File comment length
0, 0, // Disk number where file starts
0, 0, // Internal File attributes
0, 0, 0, 0, // External File attributes
0, 0, 0, 0, // Relative offset of local header file
'F', 'o', 'l', 'd', 'e', 'r', '_', 'n', 'a', 'm', 'e', '/',
// File name
// End of Central Directory Record
'P', 'K', 5, 6, // Local File Header Signature
0, 0, // Number of this disk
0, 0, // Disk where CD starts
1, 0, // Number of CD records on this disk
1, 0, // Total number of records
58, 0, 0, 0, // Size of CD
42, 0, 0, 0, // Offset of start of CD
0, 0, // Comment length
};
try ( FileOutputStream fos = new FileOutputStream( file ) )
{
fos.write(contents);
}
try ( ZipInputStream zis = new ZipInputStream( new FileInputStream( file ) ) )
{
ZipEntry entry = zis.getNextEntry();
System.out.println( entry.getName() );
}
}
}https://stackoverflow.com/questions/33347948
复制相似问题