`

使用Ftpclient从FTP上进行下载时文件少一个字节,打不开

阅读更多
[color=gray]http://blog.163.com/comfort_122/blog/static/489044092010101205144475/


[color=gray]
环境:FTP Server是Windows 2003 IIS ; 开发环境客户端是在windows下tomcat的一个web应用 ; 部署环境是在 linux redhat 下的tomcat的一个web应用。

问题:通过struts2的stream返回类型返回由ftpclient从ftp服务器上取得的文件。文件类型可能是excel或者rar压缩包。在开发环境运行正常,但部署后,发现部分excel文件和全部的rar文件下载后都无法打开。

解决:
以某个不能打开的excel文件为例子,从windows下取得的文件大小是52115字节,从linux下取得的文件大小是52114字节,原始的文件是52115字节,linux下载的少了一个什么呢?
用Beyond Compare比较两个文件的十六进制。原始的文件(或通过windows下载的)有一处是“0D 0A”,而linux下载的是“   0A”。
比较Ascii值,可以判断是由于换行符引起的问题,windows是\r\n ,而linux下是\n 。
那么意味着ftpclient取得文件时做了换行符号的转换。

如何禁止ftp传输过程的换行符转换?查阅一下ftpclient的api,里面有个setFileType方法,与我们用ftp工具或者命令行方式设置ftp传输方式一致。
看一下ftpclient类的源码 :“__fileType = FTP.ASCII_FILE_TYPE;” 。默认的传输方式是ASCII,这样确实会由于换行符引起一些问题,比如在windows下编辑shell传到服务器就常常会收到“syntax error near unexpected token” 这样的问题,可以用dos2unix命令转换行,或者将编辑器如editplus的换行格式设为unix格式。

那么在ftpclient登录成功后,和开始下载文件前设置传输类型即可。
ftpclient.login(user, password);
ftpclient.setFileType(FTP.BINARY_FILE_TYPE);

经过分析发现,linux环境与win环境的ftp操作有以下差别:
1、文件中的数据回车换行符不同
win的回车换行时:/r/n
linux的回车换行是:/n



//从FTP上下载文件并打成ZIP包给用户下载
  FTPClient ftpClient = null;
        ZipOutputStream zipOut = null;

        try {
            // 创建ftp连接对象
            ftpClient = new FTPClient();
            ftpClient.connect(FtpContants.FTP_IP, FtpContants.FTP_PORT);
            // 登陆ftp服务器
            ftpClient.login(FtpContants.FTP_USERNAME, FtpContants.FTP_PWD);
            // 设置文件的传输类型,默认是ASCII,修改为二进制
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            // printWorkingDirectory是用户的工作目录
            String basePath = ftpClient.printWorkingDirectory() + "/download/data";
            // 切换到指定目录中,如果切换失败说明目录不存在
            boolean boo = ftpClient.changeWorkingDirectory(basePath);
            // 如果切换路径失败,说明拼接的路径有问题,抛出异常
            if (!boo) {
                LogUtil.printErrorLog("the directory does not exist ,"
                        + "or the user don't hava the enterence to this directory " + basePath);
                return;
            }

            // 这个方法的意思就是每次数据连接之前,ftp client告诉ftp server开通一个端口来传输数据
            ftpClient.enterLocalPassiveMode();
            // 遍历路径下的所有文件
            FTPFile[] fileList = ftpClient.listFiles();

            response.reset();
            // 设置导出文件头
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + new String(zipFileName.getBytes(LANGUE_GBK), LANGUE_ISO));
            // 定义Zip输出流
            zipOut = new ZipOutputStream(response.getOutputStream());

            byte[] byteReader = new byte[BYTE_INIT_SIZE];
            ByteArrayOutputStream os = null;
            for (FTPFile tempFile : fileList) {
                if (tempFile.isFile()) {
                    os = new ByteArrayOutputStream();
                    String downFileName = new String(tempFile.getName().getBytes(LANGUE_GBK), LANGUE_ISO);
                    // 从FTP上下载downFileName该文件把该文件转化为字节数组的输出流
                    ftpClient.retrieveFile(downFileName, os);
                    byte[] bytes = os.toByteArray();
                    InputStream ins = new ByteArrayInputStream(bytes);

                    int len;
                    zipOut.putNextEntry(new ZipEntry(tempFile.getName()));
                    // 读入需要下载的文件的内容,打包到zip文件
                    while ((len = ins.read(byteReader)) > 0) {
                        zipOut.write(byteReader, 0, len);
                    }
                }
            }
            zipOut.flush();
        } catch (IOException e) {
            LogUtil.printErrorLog(e.getMessage());
            throw new SopSystemException(e.getMessage());
        } finally {
            // 关闭ftp连接
            if (null != ftpClient) {
                try {
                    ftpClient.disconnect();
                } catch (IOException e) {
                    LogUtil.printErrorLog("close Ftp connection error :" + e.getMessage());
                }
            }
            // 关闭zip文件输出流
            if (null != zipOut) {
                try {
                    zipOut.closeEntry();
                    zipOut.close();
                } catch (IOException e) {
                    LogUtil.printErrorLog("close ZipOutputStream connection error :" + e.getMessage());
                }
            }
        }
分享到:
评论
1 楼 菜鸟900101 2018-05-17  
真心谢谢,解决了我头疼好几天的问题,谢谢谢谢

相关推荐

    ftp4j-1.3.1下载

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能。可以将ftp4j嵌到你的Java应用中,来传输文件(包括上传和下载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp...

    JAVA上百实例源码以及开源项目

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    ftp客户端程序

    用c语言实现的ftp客户端程序,可以先下载文件头,比如文件的前512字节,用于判断文件的合法性,然后再下载剩余部分,可以将下载的文件保存到某个文件或者保存在ram。用gcc -o main ftpClient.c 即可编译生成可执行...

    java源码包---java 源码 大量 实例

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    S-FTPClient(Swing,Java,Socket,FTP,加密算法).zip

    可移植性:Java字节码可以在所有安装了JVM的设备上执行,从服务器到嵌入式系统,再到移动设备和桌面应用。 健壮性与高性能:Java通过垃圾回收机制确保内存的有效管理,同时也能通过JIT编译器优化来提升运行时性能...

    JAVA上百实例源码以及开源项目源代码

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    java源码包4

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java从网络取得文件 1个目标文件 简单 Java从压缩包中提取文件 1个目标文件 简单 Java存储与读取对象 1个目标文件 如题 Java调色板面板源代码 1个目标文件 摘要:Java源码,窗体界面,调色板 使用Java语言编写的一款...

    C#基类库(苏飞版)

    FTPClient--FTP操作帮助类,FTP上传,FTP下载,FTP文件操作,FTP目录操作 FTPHelper FTPHelper-FTP帮助类,FTP常用操作方法,添加文件,删除文件等 FTPOperater FTP操作帮助类,方法比较多,比较实用 6.JS操作...

    java源码包2

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    java源码包3

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java从网络取得文件 1个目标文件 简单 Java从压缩包中提取文件 1个目标文件 简单 Java存储与读取对象 1个目标文件 如题 Java调色板面板源代码 1个目标文件 摘要:Java源码,窗体界面,调色板 使用Java语言编写的一款...

    C#基础类库

    FTPClient--FTP操作帮助类,FTP上传,FTP下载,FTP文件操作,FTP目录操作 FTPHelper FTPHelper-FTP帮助类,FTP常用操作方法,添加文件,删除文件等 FTPOperater FTP操作帮助类,方法比较多,比较实用 6.JS操作...

    Java语言实现简单FTP软件源代码

    Java语言实现简单FTP软件源代码,供大家下载,参考参考

    Java典型模块

    3.6.3 编写一个自己的加载器 3.7 动态代理 3.7.1 什么是代理 3.7.2 动态代理基础类 3.7.3 InvocationHandler接口 3.7.4 动态代理类的设计模式 3.8 小结 第2篇 线程开发 第4章 学生并发接水(线程Thread) 4.1 学生...

Global site tag (gtag.js) - Google Analytics