`

使用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  
真心谢谢,解决了我头疼好几天的问题,谢谢谢谢

相关推荐

    获取FTP服务器上的文件大小源码

    在IT行业中,FTP(File Transfer Protocol)是一种广泛用于在互联网上传输文件的标准协议。通过FTP,用户可以连接到远程服务器,进行文件的上传、下载、查看属性等操作。本篇文章将详细讲解如何编写源码来获取FTP...

    FTPUpload上传文件 进度条显示进度

    FTP是一种用于在Internet上进行文件传输的标准协议。Java提供了一个内置的`java.net.FTPClient`类,可以方便地进行FTP操作。为了实现文件上传,我们需要创建一个`FTPClient`实例,连接到FTP服务器,然后调用`...

    java大文件上传至ftp服务器带进度条显示的

    此类可能会有一个`uploadFile`方法,接收大文件和FTPClient实例作为参数,内部使用`java.nio`包进行高效的文件读取和上传。 总的来说,实现Java大文件上传至FTP服务器并显示同步进度条涉及的关键技术点包括:...

    FTP远程上传下载文件

    FTP(File Transfer Protocol)是一种广泛使用的网络协议,用于在互联网上进行文件传输。在这个场景中,我们使用FTP协议来实现在远程服务器上上传和下载文件的功能。C#和Asp.NET是开发此类应用的主要编程语言和技术...

    java下载ftp文件.txt

    根据给定文件的信息,本文将详细介绍如何利用Java代码来实现从FTP服务器下载文件的过程,并对代码中的关键步骤进行深入解析。 ### Java下载FTP文件 在实际应用开发中,经常需要与FTP服务器进行交互,比如上传文件...

    java登录FTP下载文件,支持断点下载

    在Java编程环境中,FTP(File Transfer Protocol)文件下载是一个常见的任务,特别是在处理大量数据传输时。本场景中,我们关注的重点是如何实现一个功能完善的FTP下载工具,它支持断点续传,即当下载中断后可以从...

    FTPClient上传下载(支持断点续传)

    FTP(File Transfer Protocol)是一种用于在网络上进行文件传输的标准协议,主要用于在不同主机之间传输文件。`FTPClient`是Apache Commons Net包中的一个类,提供了一种简单的方式来实现FTP客户端的功能,包括文件...

    ftp4j-1.3.1下载

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

    FtpClient(源码)

    FTPClient是一款基于C# 2.0开发的Windows应用程序,它实现了FTP(文件传输协议)客户端的功能,允许用户与FTP服务器进行交互,如上传、下载、列出目录、删除文件等。这个源码对于学习和理解网络编程,尤其是FTP协议...

    FTP上传下载文件

    FTP(File Transfer Protocol)是一种广泛使用的网络协议,用于在互联网上进行文件的上传和下载。FTP使得用户可以方便地在本地计算机与远程服务器之间交换数据。在这个场景中,我们主要探讨FTP客户端如何实现文件的...

    java ftp实现文件的上传、下载

    为了提高效率,可以考虑使用FTP的批量操作,例如,如果需要上传或下载多个文件,可以一次性设置传输模式,然后在一个会话中处理所有文件。 8. **安全性考虑** 虽然FTP是常见的文件传输方式,但它不提供内置的加密...

    Android 使用FTP文件传输协议上传文件(支持断点续传 )

    在上传文件时,使用`FTPClient`的`storeFile()`方法,并传递当前已上传的字节数: ```java OutputStream outputStream = null; try { outputStream = ftpClient.storeFileStream("remote_file_path"); ...

    ftp上传下载工具类

    FTP(File Transfer Protocol)是一种广泛使用的网络协议,用于在互联网上进行文件的传输。FTP上传下载工具类通常是指一个编程接口或代码库,为开发者提供便捷的FTP客户端功能,包括连接到FTP服务器、上传文件、下载...

    java FTP断续上传与下载

    FTP(File Transfer Protocol)是一种用于在网络上进行文件传输的标准协议,而断续上传和下载则是FTP协议的一个扩展功能,允许用户在文件传输过程中暂停并继续,避免了因网络中断或其他问题导致的文件传输失败。...

    WPF ftp上传下载支持断点续传

    为了在WPF应用中实现FTP功能,我们需要使用一个支持FTP的库,如`System.Net.FtpClient` 或第三方库如 `FluentFTP`。这些库提供了FTP命令的封装,使开发者能够方便地进行文件操作。 接下来,我们关注断点续传。断点...

    java Ftp上传下载

    2. **Java FTP库**:Java标准库提供了一个名为`java.net.Socket`的类来处理基本的FTP连接,但通常开发人员会使用更高级的库,如Apache Commons Net库,它提供了一个完善的FTPClient类,简化了FTP操作。 3. **Apache...

    用Java实现FTP批量大文件上传下载.doc

    具体做法是在FTP客户端库提供的接口中注册一个监听器,监听文件传输过程中的字节变化,从而计算当前传输的百分比。 ```java ftpClient.addTransferListener(new TransferListener() { public void bytes...

    Java实现ftp文件上传下载解决慢中文乱码多个文件下载等问题

    在Java中实现FTP(File Transfer Protocol)文件上传和下载时,可能会遇到各种问题,如速度慢、中文乱码以及多文件下载等。以下将详细解释如何解决这些问题,并提供相关的代码示例。 首先,针对文件上传慢的问题,...

    FTP上传实例(带进度条)

    FTP(File Transfer Protocol)是一种广泛使用的互联网协议,用于在不同网络之间传输文件。在这个实例中,我们关注的是如何实现一个带有进度条的FTP文件上传功能。这个FTP上传实例提供了可视化的进度反馈,使得用户...

    FTP上传下载工具

    在这个“FTP上传下载工具”中,开发者使用Java语言构建了一个功能强大的客户端应用,它能够实现文件和文件夹的上传与下载,并且带有进度显示,极大地提高了用户在处理大文件时的体验。 1. **Java FTP库**: 这个...

Global site tag (gtag.js) - Google Analytics