导语:

  昨天接到项目经理这么一个需求,让我在POI导出Excel的时候写一份到我之前搭建的ftp服务器上。所以就有了这篇博客首先我们来分析下之前的业务逻辑:我们创建并构造了一个workbook,然后构建了一个OutputStream输出流,然后我们把数据写入输出流中就可以被客户端下载。

  现在我们要在此基础上写一份到ftp服务器

  那么我们就需要两个流,首先一个输入流把文件写到ftp服务器,然后需要一个输出流把文件输出到客户端。千万不要用workbook.write(out)一份到客户端,然后又workbook.write(in)一份到ftp,会报错的。Stream is closed,(为啥报错,我也解释不清希望大神解惑一下)

  正确思路应该是先写一份到ftp服务器,然后再读取这个文件,然后再把这个文件输出给客户端

参考:

ftp服务器搭建(离线安装vsftpd),配置

poi实现百万级数据导出

来看代码吧:

1. 我们只需要对 oi实现百万级数据导出 中的 CommentController  稍作修改,然后配合一些工具类就可以实现

/**
* excel导出功能
* @param commentSearch
* @param response
* @param request
* @return
* @throws Exception
*/
@RequestMapping("/exportCommentInfo")
@ResponseBody
@NoRepeatRequest
public BaseDTO exportCommentInfo(CommentSearch commentSearch, HttpServletResponse response, HttpServletRequest request) throws Exception{
LOGGER.info("CommentController.exportCommentInfo start");
long startTime = System.currentTimeMillis();
LOGGER.info("开始下载.........................................");
List<ErrorInfo> errors = null;
int result = ;
String fileName = FileNameUtils.getExportCommontExcelFileName();
OutputStream fileOut = null;
SXSSFWorkbook workbook = null;
try {
LOGGER.debug("classpath: " + fileName);
workbook = new SXSSFWorkbook();
commentService.exportCommentInfo(request,workbook, commentSearch);
// 定义excel文件名
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=\""
+ URLEncoder.encode(fileName, "UTF-8") + "\"");
// 定义输出流
fileOut = response.getOutputStream();
// 调用导出方法
//workbook.write(fileOut);
//写一份到ftp服务器
ByteArrayOutputStream os = new ByteArrayOutputStream();
workbook.write(os);
byte[] b = os.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(b);
FtpUtil.uploadFileToFtp(fileName,in,fileOut);

       workbook.dispose();
} catch (Exception e) {
LOGGER.error("InterfaceInfoController.exportInterfaceInfo Exception: ", e);
ErrorInfo errorInfo = new ErrorInfo("system.error", "系统异常!");
errors = Arrays.asList(errorInfo);
request.getSession().setAttribute("exportStatus","error");
}finally {
fileOut.close();
workbook.close();
}
LOGGER.info("下载完成....|||||.......用时:" + (System.currentTimeMillis() - startTime));
return tranferBaseDTO(errors, result);
}

1.首先把workbook写到 ByteArrayOutputStream 输出流中,然后转换成 字节数组 byte[] b 在转换成 ByteArrayInputStream 输入流用来写入ftp

       ByteArrayOutputStream os = new ByteArrayOutputStream();
workbook.write(os);
byte[] b = os.toByteArray();
ByteArrayInputStream in = new ByteArrayInputStream(b);
FtpUtil.uploadFileToFtp(fileName,in,fileOut);

2.然后转换成 字节数组  在转换成输入流用来写入ftp ,主要看这几个方法

/**
* 上传重载 二进制流
* @param filename
* @param input
* @return
*/
public static boolean uploadFileToFtp(String filename, ByteArrayInputStream input, OutputStream fileOut) {
getPropertity();
return uploadFileToFtp( host, port, username, password, basePath,
filePath, filename, input, fileOut);
} /**
* Description: 向FTP服务器上传文件 二进制流文件
* @param host FTP服务器hostname
* @param port FTP服务器端口
* @param username FTP登录账号
* @param password FTP登录密码
* @param basePath FTP服务器基础目录
* @param filePath FTP服务器文件存放路径。例如分日期存放:/2015/01/01。文件的路径为basePath+filePath
* @param filename 上传到FTP服务器上的文件名
* @return 成功返回true,否则返回false
*/
public static boolean uploadFileToFtp(String host, String port, String username, String password, String basePath,
String filePath, String filename, ByteArrayInputStream input, OutputStream fileOut) {
FTPClient ftp = new FTPClient();
try {
//开启ftp连接
boolean result = connectFtp(ftp, host, port, username, password, basePath, filePath);
if(!result){
return result;
}
if (FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK).
if (FTPReply.isPositiveCompletion(ftp.sendCommand("OPTS UTF8", "ON"))) {
LOCAL_CHARSET = "UTF-8";
}
}
       //防止中文乱码
filename = new String(filename.getBytes(LOCAL_CHARSET),SERVER_CHARSET );
//为了加大上传文件速度,将InputStream转成BufferInputStream , InputStream input
BufferedInputStream in = new BufferedInputStream(input);
//加大缓存区
ftp.setBufferSize(1024*1024);
//设置上传文件的类型为二进制类型
ftp.setFileType(FTP.BINARY_FILE_TYPE);
//上传文件
if (!ftp.storeFile(filename, in)) {
return false;
}
//写一份给客户端
FTPFile[] fs = ftp.listFiles();
for (FTPFile ff : fs) {
if
(ff.getName().equals(filename)) {
ftp.retrieveFile(ff.getName(), fileOut);
fileOut.close();
}
}

in.close();
ftp.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return true;
} /**
* 连接ftp服务器并切换到目的目录
* 调用此方法需手动关闭ftp连接
* @param ftp
* @param host
* @param port
* @param username
* @param password
* @param basePath
* @param filePath
* @return
*/
private static boolean connectFtp( FTPClient ftp,String host, String port, String username, String password, String basePath, String filePath){
boolean result = false;
try {
int portNum = Integer.parseInt(port);
int reply;
// 连接FTP服务器
ftp.connect(host, portNum);
// 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
ftp.login(username, password);
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
//切换到上传目录
if (!ftp.changeWorkingDirectory(basePath+filePath)) {
//如果目录不存在创建目录
String[] dirs = filePath.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) {
continue;
}
tempPath += "/" + dir;
if (!ftp.changeWorkingDirectory(tempPath)) {
if (!ftp.makeDirectory(tempPath)) {
return result;
} else {
ftp.changeWorkingDirectory(tempPath);
}
}
}
}
result = true;
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}

主要是  我们为了加快文件上传速度把刚才传入的 ByteArrayInputStream 转换成了  BufferedInputStream 

BufferedInputStream in = new BufferedInputStream(input);

然后我们把  BufferedInputStream 写入到ftp服务器

ftp.storeFile(filename, in)

到这里第一步就完成了,接下来是从服务器下载我们刚才上传 文件,然后通过刚才传入的 输出流 fileOut 输出到客户端

 //写一份给客户端
FTPFile[] fs = ftp.listFiles();
for (FTPFile ff : fs) {
if (ff.getName().equals(filename)) {
ftp.retrieveFile(ff.getName(), fileOut);
fileOut.close();
}
}

POI导出时写一份到ftp服务器,一份下载给客户端的更多相关文章

  1. 使用批处理文件在FTP服务器 上传下载文件

    1.从ftp服务器根目录文件夹下的文件到指定的文件夹下 格式:ftp -s:[配置文件] [ftp地址] 如:ftp -s:c:\vc\ftpconfig.txt   192.168.1.1 建立一个 ...

  2. Spring学习---Spring中利用组件实现从FTP服务器上传/下载文件

    FtpUtil.java import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExcepti ...

  3. ftp服务器上传下载共享文件

    1 windows下搭建ftp服务器 https://blog.csdn.net/qq_34610293/article/details/79210539 搭建好之后浏览器输入 ftp://ip就可以 ...

  4. POI导出时,将指定的列设置为下拉列表

    本示例设置第2列为下拉框(下拉框内容为:是/否),从第5行开始到5657行结束. 关键代码示例: ComboxList = new String[]{"是","否&quo ...

  5. WordPress更新时提示无法连接到FTP服务器的解决方案

    这几天在搭建主站的时候,更新wordpress时无法连接到FTP原因服务器 解决方法如下: 在WordPress目录下找到wp-config.php文件并编辑,在最后一行加上: define('FS_ ...

  6. 从ftp服务器进行批量下载,处理文件名保存时重名的问题,更改重名文件名方式为给后面加1、2、3等数字,保持后缀不变

    公司最近有一个从ftp批量下载文件的需求,但是文件名重复总会报错 没办法,自己下班后写了一个小算法 仿照桶排序的原理,实现了这个小功能,直接上代码: String[] test = {"ha ...

  7. Node.js使用ftp连接远程ftp服务器枚举和下载文件示例

    示例代码: var Ftp = require('ftp'); var fs = require('fs'); var path = require('path'); // 首先判断参数中是否包含{d ...

  8. FTP服务器的搭建与配置

    主要来源:http://www.cnblogs.com/helonghl/articles/5533857.html 1.安装FTP服务器: yum install vsftpd -y 2.启动FTP ...

  9. Ubantu下FTP服务器资源进行控制

    在FTP服务器的管理中无论对本地用户还是匿名用户,对于FTP服务器资源的使用都需要进行控控制, 避免由于负担过大造成FTP服务器运行异常, 可以添加以下配置项对FTP客户机使用FTP服务器资源进行控制 ...

随机推荐

  1. django ORM常用查询条件

    假设有一个模型 class Article(models.Model): title=models.CharField(max_length=50) content=models.TextField( ...

  2. memset与malloc性能测试(转)

    前一段跟同事聊项目组已有的一些工具,同事讲里面有太多的malloc与memset,对性能的影响比较大,因此今天就在自己的机器上测试了这两个函数,不多说,上数据.测试环境:2.2GHZ.2G内存mems ...

  3. android拨号

    android:textColor="#A0ff1400" A0表示透明度00完全透明FF完全不透明,后面6位是RGB问题:类中类的findViewById方法为何用不了?解:类中 ...

  4. 2018年北京信息科技大学第十届程序设计竞赛暨ACM选拔赛题解

    链接:https://www.nowcoder.com/acm/contest/118/A 来源:牛客网 PUBG 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语 ...

  5. topcoder srm 425 div1

    problem1 link 暴力搜索即可. problem2 link 可以将每次所有的piece的位置看作一个状态,由于$C_{25}^{5}=53130$,所以最多有这么多状态.这里可以加一些优化 ...

  6. topcoder srm 698 div1 -3

    1.定义重复串$S=T+T$,即$S$可以表示成一个串的叠加.给定一个串$s$,可以通过删除字符.修改字符.增加字符来使得其变为重复串.问最少的次数. 思路:首先将$s$分成个串$s_{0},s_{1 ...

  7. com.fasterxml.jackson.databind.JsonMappingException

    背景 在搭建SSM整合activiti项目时,在查找activiti定义的流程模板时,前台不能够接受到ProcessDefinition这个对象. 原因 ProcessDefinition是一个接口, ...

  8. uniGUI试用笔记(七)

    uniGUI的文件下载由于TUniSession的存在而变得非常简单,最典型的一个例子就是将列表中的所有数据导出到Excel中.服务器上采用TMS FlexCel控件,先将数据集中的记录导入到Exce ...

  9. Python3 tkinter基础 Canvas bind 鼠标左键点击时,在当前位置画椭圆形

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  10. 如何查看sonarqube的版本

    Server Logs & System Info The System Info page is found at Administration > System. It gives ...