前言
以前写ftp上传使用buff上传append拼接,今天使用了循环拼接,但是缺点确实不能flush
总结一下,以备后用
引入依赖
commons-net-1.4.1.jar
maven下载
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>1.4.1</version>
</dependency>
自定义FTP工具类
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.SocketException;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
/**
* 〈FTP工具类〉<br>
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class FTPUtil {
private FTPClient ftpClient;
public static final int BINARY_FILE_TYPE = FTP.BINARY_FILE_TYPE;
public static final int ASCII_FILE_TYPE = FTP.ASCII_FILE_TYPE;
static Logger logger = org.slf4j.LoggerFactory.getLogger(FTPUtil.class);
/**
* 使用详细信息进行ftp服务器连接: <br>
* 〈功能详细描述〉
*
* @param host :服务器地址名称
* @param port :端口号
* @param user :用户名
* @param password :appendFile
* @param path :转移到FTP服务器目录
* @throws SocketException
* @throws IOException
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public void connectServer(String host, int port, String user, String password, String path) throws SocketException,
IOException {
ftpClient = new FTPClient();
ftpClient.connect(host, port);
ftpClient.login(user, password);
if (path != null && path.length() != 0) {
boolean changeok = ftpClient.changeWorkingDirectory(path);
if (!changeok) {
// 变更目录失败,生成目录
ftpClient.mkd(path);
ftpClient.changeWorkingDirectory(path);
}
}
ftpClient.setBufferSize(1024);// 设置上传缓存大小
ftpClient.setControlEncoding("UTF-8");// 设置编码
ftpClient.setFileType(BINARY_FILE_TYPE);// 设置文件类型
}
/**
* 关闭连接
*
* @throws IOException
*/
public void closeServer() throws IOException {
if (ftpClient != null && ftpClient.isConnected()) {
ftpClient.logout();// 退出FTP服务器
ftpClient.disconnect();// 关闭FTP连接
}
}
/**
* 删除服务器上的文件
*
* @param pathName
* @return
* @throws IOException
*/
public boolean deleteFile(String pathName) throws IOException {
return ftpClient.deleteFile(pathName);
}
/**
* 以流的方式上传文件到ftp服务器: <br>
* 〈功能详细描述〉
*
* @param iStream :输入流
* @param remoteFileName :上传到服务器的文件名称
* @return
* @throws IOException
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public boolean uploadFile(InputStream iStream, String remoteFileName) throws IOException {
boolean flag = false;
try {
// 将文件名转码,防止中文文件名上传失败失败问题,
flag = ftpClient.storeFile(new String(remoteFileName.getBytes("UTF-8"), "iso-8859-1"), iStream);
} catch (IOException e) {
flag = false;
logger.error("uploadFile 文件转码失败 :" + e);
return flag;
} finally {
if (iStream != null) {
iStream.close();
}
}
return flag;
}
//追加写入
public boolean appendFile(String remote, InputStream local) throws IOException {
return ftpClient.appendFile(remote, local);
}
//获取写入流
public Writer getRemoteFileWriter (String remoteFileName) throws IOException {
OutputStreamWriter writer = null;
try {
writer = new OutputStreamWriter(ftpClient.appendFileStream(remoteFileName));
/*
BufferedWriter bw = new BufferedWriter(out);
bw.write("\n"+versionCode+path);
bw.flush();
bw.close();
out.close();*/
} catch (IOException e) {
return null;
}
return writer;
}
/**
* 从ftp服务器上下载文件到本地输入流: <br>
* 〈功能详细描述〉
*
* @param sourceFileName :服务器资源文件名称
* @param oStream :本地输入流
* @throws IOException
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public void retrieveFile(String sourceFileName, OutputStream oStream) throws IOException {
ftpClient.retrieveFile(new String(sourceFileName.getBytes("UTF-8"), "iso-8859-1"), oStream);
}
/**
* 上传文件,从ftp服务器上拿到OutputStream,往流中写入数据: <br>
* 〈功能详细描述〉
*
* @param remoteFileName
* @return
* @throws IOException
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public OutputStream storeUniqueFileStream(String remoteFileName) throws IOException {
OutputStream oStream = ftpClient.storeUniqueFileStream(remoteFileName);
return oStream;
}
// 下载ftp上面的文件,自定义下载文件名称 、
public void downLoad(String remoteFileName, String fileName) {
try {
ftpClient.retrieveFile("/" + remoteFileName, new FileOutputStream(fileName));
} catch (FileNotFoundException e) {
logger.error(e.getMessage(), e);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
/**
* 从ftp服务器上获取上传的文件 <br>
* 〈功能详细描述〉
*
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public List<FTPFile> getListFiles(String ftpFilePath) {
try {
List<FTPFile> fileList = Arrays.asList(ftpClient.listFiles(ftpFilePath));
return fileList;
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return null;
}
}
上传文件
public void uploadFileTest() {
// 要写入的文件内容
String fileContent = "hello world,你好世界";
// 创建的文件
String fileName = "ftp.txt";
// ftp服务器地址
@Value("${ftp.host}")
private String host;
// ftp端口号
@Value("${ftp.port}")
private int port;
// ftp用户名称
@Value("${ftp.username}")
private String username;
// ftp密码
@Value("${ftp.pwd}")
private String pwd;
// ftp工作目录
@Value("${ftp.wdtrade.location}")
private String location;
FTPUtil ftpUtil = new FTPUtil();
try {
//连接ftp
ftpUtil.connectServer(host, port, username, pwd, location);
// 写入文件
ftpUtil.uploadFile(new ByteArrayInputStream(fileContent.getBytes()), fileName );
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
文件下载
//服务器上获取文件名 或者页面传过来文件名
String fileUrl = request.getParameter("fileUrl");
response.setContentType("application/x-download");
response.addHeader("Content-Disposition", "attachment;filename=" + fileUrl);
OutputStream os = response.getOutputStream()
FTPUtil ftpUtil = new FTPUtil();
logger.info("从服务器{}获取文件{},{}", host, fileName);
try {
// 连接FTP服务器
ftpUtil.connectServer(host, port, username, pwd, location);// 连接ftp服务器
// 开始读取文件到浏览器
ftpUtil.retrieveFile(fileName, os);
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new BizFailException(ErrorCodeConstants.NOT_FOUND, "ftp上没有上传的文件");
} finally {
try {
// 关闭流
os.close();
} catch (IOException e) {
logger.error("关闭os流失败{}", e);
}
try {
// 释放FTP连接
ftpUtil.closeServer();
} catch (IOException e) {
logger.error("关闭ftp服务失败{}", e);
}
}
}
第一种写法
jdk自带换行符: System.getProperty(“line.separator”)
这也是换行符,功能和"\n"是一致的,但是此种写法屏蔽了 Windows和Linux的区别 ,更保险一些.
//换行符加上bytes格式
try{
//连接
ftpUtil.connectServer(host, port, username, pwd, location);
String head = CSVUtil.joinByLineSeparator(Arrays.asList(CSVUtil.joinByCommas(new String[] { "xxx", "xxx", "xxx" })));
// 上传文件头
ftpUtil.uploadFile(new ByteArrayInputStream(head.getBytes()), 文件名);
//获取成字节
byte[] csvBytes = (System.getProperty("line.separator") + wirteInforList(resultWirtList)).getBytes();
boolean isSuccess = ftpUtil.appendFile(文件名,
new ByteArrayInputStream(csvBytes));
if (!isSuccess) {
logger.error("--------追加数据失败--------------");
return false;
}
private String wirteInforList(List<ConsumptionInfoDto> resultWirtList) throws IOException {
List<String> exchangeOrderRows = map(new Function<ConsumptionInfoDto, String>() {
@Override
public String apply(ConsumptionInfoDto consumptionInfoDto) {
return CSVUtil.joinByCommas(convertNull(Arrays.asList(consumptionInfoDto.getCardNo() + "\t",
consumptionInfoDto.getBizOrderNo() + "\t", consumptionInfoDto.getPartnerOrderNo() + "\t",
new SimpleDateFormat("yyyy-MM-dd").format(consumptionInfoDto.getTradeTime()) + "\t",
consumptionInfoDto.getWdCardNo() + "\t", consumptionInfoDto.getWdStoreCode() + "\t")));
}
}, resultWirtList);
return CSVUtil.joinByLineSeparator(Arrays.asList(CSVUtil.joinByLineSeparator(exchangeOrderRows)));
}
}catch (Exception e) {
logger.error("上传FTP失败", e);
return false;
} finally {
try {
ftpUtil.closeServer();
} catch (IOException e) {
logger.error("IO异常", e);
}
}
// 转换工具类 CSV
static class CSVUtil {
static String joinByCommas(String[] cols) {
List<String> colList = Arrays.asList(cols);
return joinByCommas(colList);
}
static String joinByCommas(List<String> colList) {
return join(colList, ",");
}
static String joinByLineSeparator(String[] lines) {
List<String> lineList = Arrays.asList(lines);
return joinByLineSeparator(lineList);
}
static String joinByLineSeparator(List<String> lineList) {
return join(lineList, System.getProperty("line.separator"));
}
static String join(List<String> strList, String separator) {
if (CollectionUtils.isEmpty(strList)) {
return "";
} else if (strList.size() > 1) {
String first = StringUtils.isNotEmpty(strList.get(0)) ? strList.get(0) : "";
return first.concat(separator).concat(join(strList.subList(1, strList.size()), separator));
} else {
return strList.get(0);
}
}
}
// 定义map
static <I, O> List<O> map(Function<I, O> function, List<I> iList) {
List<O> oList = new ArrayList<O>();
if (CollectionUtils.isEmpty(iList)) {
return oList;
}
for (I input : iList) {
O output = function.apply(input);
oList.add(output);
}
return oList;
}
// 定义接口
interface Function<I, O> {
O apply(I input);
}
// 定义如果为空那么设置为空字符串
private List<String> convertNull(List<String> list) {
List<String> listStr = new ArrayList<String>();
for (String str : list) {
if (str.equals(null + "\t")) {
str = " ";
}
listStr.add(str);
}
return listStr;
}
这种写法比较简洁,把工具类封装一下,System.getProperty(“line.separator”)再封装为字符串,非常简洁干净但是唯一缺点不好flush
第二种写法
private boolean executeUpload(final WdTradeBatch wdTradeBatch) {
// 连接ftp
FTPUtil ftpUtil = new FTPUtil();
OutputStream os = null;
BufferedWriter bw = null;
try {
// step 5 :连接ftp
ftpUtil.connectServer(host, port, username, pwd, location);
// 原批次如果失败,删除原文件
if (FAIL.equals(wdTradeBatch.getStatus())) {
boolean delRes = ftpUtil.deleteFile(wdTradeBatch.getFileUrl());
if (!delRes) {
throw new BizFailException("文件删除失败");
}
}
os = ftpUtil.getRemoteFileOs(wdTradeBatch.getFileUrl());
bw = new BufferedWriter(new OutputStreamWriter(os));
// 上传文件头
String head = new String(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF })
+ CSVUtil.joinByLineSeparator(Arrays.asList(CSVUtil.joinByCommas(new String[] { "xxx", "xxx", "xxx" })));
bw.write(head);
//ftpUtil.uploadFile(new ByteArrayInputStream(head.getBytes()), wdTradeBatch.getFileUrl());
// 上传文件详情数据
return consumptionRecordUpload(bw, wdTradeBatch);
} catch (Exception e) {
logger.error("上传FTP失败", e);
return false;
} finally {
try {
bw.close();
os.close();
ftpUtil.closeServer();
} catch (IOException e) {
logger.error("IO异常", e);
}
}
}
private boolean consumptionRecordUpload(BufferedWriter bw,WdTradeBatch wdTradeBatch) throws IOException {
ArrayList<x> resultWirtList = new ArrayList<x>();
while (true){
resultWirtList .add(1);
if (resultWirtList.size() >= 100) {
String content = System.getProperty("line.separator") + wirteInforList(resultWirtList);
bw.write(content);
bw.flush();
resultWirtList = new ArrayList<ConsumptionInfoDto>();
}
if (CollectionUtils.isNotEmpty(resultWirtList)) {
String content = System.getProperty("line.separator") + wirteInforList(resultWirtList);
bw.write(content);
bw.flush();
}
}