如何在Java Struts中动态生成CSV文件并上传至FTP服务器
解决方案:内存生成CSV并直接上传FTP
原代码存在的问题
- 使用
FileWriter将CSV落地到本地磁盘,不符合无磁盘IO的需求 - 直接调用
business.toString()和position.toString()会输出数组内存地址,而非实际数据内容 FileWriter并没有getInputStream()方法,这段代码会抛出编译错误
修改后的实现思路
利用内存流(ByteArrayOutputStream + ByteArrayInputStream)在内存中构建CSV内容,无需落地文件,直接将内存流转为输入流传给FTP上传方法。同时正确处理CSV格式,将数组数据按规范写入。
完整修改代码
public ActionForward generatePayroll(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { SessionInfoForm _form = (SessionInfoForm) form; SisTransactionsSession _config = _form.getSisTransactionsSession(); String loggedInUser = _form.getLoggedinEmployeeDVO().getLoginId().toUpperCase(); String[] business = request.getParameterValues("selectedBusinessValues"); String[] position = request.getParameterValues("selectedPositionValues"); InputStream isFixedValue = null; try { // 使用内存流替代文件流,避免磁盘IO ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(baos, StandardCharsets.UTF_8); BufferedWriter writer = new BufferedWriter(osw); // 写入CSV表头(按需调整) writer.write("Business,Position"); writer.newLine(); // 逐行写入数据:假设business和position数组长度一致 if (business != null && position != null && business.length == position.length) { for (int i = 0; i < business.length; i++) { // 处理CSV特殊字符:内容含逗号/引号时用双引号包裹 String businessVal = escapeCsvField(business[i]); String positionVal = escapeCsvField(position[i]); writer.write(businessVal + "," + positionVal); writer.newLine(); } } // 刷新并关闭写入流 writer.flush(); writer.close(); // 将内存输出流转为输入流,用于FTP上传 isFixedValue = new ByteArrayInputStream(baos.toByteArray()); // 调用FTP上传方法,替换为实际目标目录 String dirName = "/ftp/payroll"; String fileName = "PAYROLL_PRM.csv"; fileUpload(isFixedValue, dirName, loggedInUser, fileName); } catch (IOException e) { e.printStackTrace(); } finally { // 确保输入流被关闭,避免资源泄漏 if (isFixedValue != null) { try { isFixedValue.close(); } catch (IOException e) { e.printStackTrace(); } } } return mapping.findForward("success"); } // CSV字段转义工具方法,符合RFC 4180标准 private String escapeCsvField(String field) { if (field == null) { return ""; } // 字段含逗号、双引号或换行时,用双引号包裹并转义内部双引号 if (field.contains(",") || field.contains("\"") || field.contains("\n") || field.contains("\r")) { return "\"" + field.replace("\"", "\"\"") + "\""; } return field; }
关键改动说明
- 无磁盘IO:用
ByteArrayOutputStream在内存中构建CSV内容,完全跳过本地文件操作 - 规范CSV格式:遍历数组写入每行数据,添加字段转义逻辑,避免格式错误
- 流转适配:将内存输出流转换为输入流,直接适配已有的
fileUpload方法 - 资源管理:添加finally块确保输入流被正确关闭,避免资源泄漏
内容的提问来源于stack exchange,提问作者Kannuri
相关产品推荐
相关产品推荐

