我支持的ColdFusion应用程序安装在两个不同的位置。一个位置运行带有ColdFusion 9和MS SQL Server 2008的Windows Server 2008,另一个位置运行带有ColdFusion 11和MS SQL Server 2012的Windows Server 2012.应用程序使用CFZIP action = "zip"
提供导出过程,然后使用zip文件使用CFZIP action = "unzip"
在目标计算机上导入。
以下是我必须生成用于导出的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:只有DEFLATED条目可以有EXT描述符
我们在ColdFusion 9服务器上使用CFZIP
解压缩在ColdFusion 11服务器上使用CFZIP
生成的zip文件时才会遇到此问题。我可以在ColdFusion 9服务器上提取从ColdFusion 11生成的zip文件的内容,使用7Zip创建一个新的Zip文件,其中包含原始ColdFusion 11生成的zip文件的确切内容,我没有得到错误。
每当我们测试从ColdFusion 11源到ColdFusion 11目的地或从ColdFusion 9源到ColdFusion 9目的地时,该过程都能正常工作。我们只是在使用ColdFusion 11并试图解压ColdFusion 9时遇到问题。我已经搜索过Google,但似乎无法找到这样的问题。任何帮助将不胜感激。
答案 0 :(得分:0)
<强> [TL / DR] 强>
CFZip
符合比PKZIP 2.04g晚的zip规范ZipInputStream
(CF9似乎使用)符合严格符合PKZIP 2.04g(或更早版本)规范。两个版本之间的细微差别是它们处理零长度条目(即子目录或mime类型等)。 CF11中的CFZip
将这些条目标记为STORED
,没有压缩(直观地,在规范的更高版本中,它是正常的,因为它们是零长度,因此压缩不会对它们做任何事情)但是ZipInputStream
(在CF9中由CFZip
调用)期望使用DEFLATE
方法将它们标记为压缩。
如果您没有零长度条目,那么生成的文件是ColdFusion 可能能够使用java {{1}读取(我认为他们会但最终无法证明) };但是,如果你有零长度的文件,那么它会抛出错误。
或者,要么:
ZipInputStream
以外的其他内容,能够读取符合以后标准的zip文件(即您可以使用CFZip
在ColdFusion外部运行7zip或使用java cfexecute
ColdFusion里面的库);或org.apache.commons.compress
以外的内容,将其创建的zip文件限制为早期标准(见下文)。详细解答:
从Zip Format Specification部分4.4.4通用位标志:
位3:如果设置此位,则压缩字段crc-32 大小和未压缩的大小在中设置为零 本地标题。正确的值放在 紧接着压缩后的数据描述符 数据。 (注意:仅限DOS的PKZIP版本2.04g 识别此位用于方法8压缩,更新 PKZIP的版本可以识别这个位 压缩方法。)
当本地文件头指示zip文件中存在零长度条目时(即一个目录或zip文件中的某些其他内容,如嵌入式mime类型),此位置位。
在PKZIP版本2.04g(或更早版本)标准下,它会期望压缩方法标志设置为CFZip
(方法8压缩)。 Java的DEFLATE
符合严格到此标准,如果找不到此压缩方法,则会抛出ZipInputStream
(带有消息ZipException
)(请参阅source code here })。
only DEFLATED entries can have EXT descriptor
似乎将压缩方法设置为cfzip
(方法0压缩 - 或不压缩)。根据我的阅读,这符合PKZIP标准的更高版本,但不向后兼容STORED
类中Java实现的标准版本。
如何缓解此问题:
ZipInputStream
中的recurse
选项);或CFZip
。CFZip
但使用其他内容解压缩CF9中与更多压缩算法兼容的文件(即使用CFZip
调用外部程序来处理zip文件;使用java cfexecute
库;等)。如果你选择2并希望使用与eariler版本兼容的东西,那么这对我有用,我可以使用org.apache.commons.compress
解压缩文件(直接在Java中测试,因为我没有CF9):
ZipInputStream
(注意:错误处理是最小的,因此如果您打算在生产环境中使用它,您可能希望使其更加健壮。)
如果编译该java类并将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] );
}
}
}
}
}
文件放在类路径的.class
子目录中(可以在ColdFusion管理面板中添加条目)。
然后你可以使用:
来调用它zip
<强>测试强>
如果你想测试一下这是怎么回事,那么这会产生一个有效的zip文件,在后面的特定情况下会生成错误:
<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>