简单教学,复制即用的Ftp下载图片
引入配置包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.9.0</version>
</dependency>
首先创建连接客户端,中间如果赋值进去找不到变量,则是自己需要配置的 ,比如host:则表示主机ip
public FTPClient connFtp() {
FTPClient ftpClient = null;
String errorMsg = null;
try {
ftpClient = new FTPClient();
//设置连接超时时间
ftpClient.setConnectTimeout(1000 * 30);
// 连接FTP服务器
if (port == 0) {
ftpClient.connect(host);
} else {
ftpClient.connect(host, port);
}
// 登陆FTP服务器
ftpClient.login(user, pwd);
// 中文支持 ,避免图片或文件中文乱码
ftpClient.setControlEncoding("GBK");
FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
conf.setServerLanguageCode("zh");
// 设置文件类型为二进制(如果从FTP下载或上传的文件是压缩文件的时候,不进行该设置可能会导致获取的压缩文件解压失败)
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
ftpClient.disconnect();
Assert.isTrue(false, ERROR_CONN + "用户名或密码错误");
} else {
log.info("FTP连接成功!");
}
} catch (Exception e) {
log.info("登陆FTP失败,请检查FTP相关配置信息是否正确!" + e);
Assert.isTrue(false, ERROR_CONN + e.getMessage());
return null;
}
return ftpClient;
}
// deviceId :其实这个是文件名,拼接的,只是我们这以这个id存的文件名,所以用这个
// batch 主要是判断是否需要批量
@Override
public List<MultipartFile> getFtpImage(String deviceId, boolean batch) {
FTPClient ftpClient = connFtp();
String imgUrl = null;
List<MultipartFile> fileList = new ArrayList<>();
try {
String path = null;
String filename = null;
//指定文件路径 和 路径下的文件名
path = "/5/panorama/";
filename = "5_"+deviceId+".jpg";
//这一步很重要,主要是类似打开目录,
ftpClient.changeWorkingDirectory(path);
if(batch){
FTPFile[] ftpFiles = ftpClient.listFiles();//获取目录下面文件列表,在下面
for (int i =0;i<ftpFiles.length;i++){
FTPFile ftpFile = ftpFiles[i];
if (ftpFile.getName().equals(filename)) {
// 此处表示直接返回到浏览器下载,需要添加参数 HttpServletResponse
// response.setHeader("Content-disposition","attachment;filename="+ URLEncoder.encode(filename, "utf-8"));
// 将文件保存到输出流outputStream中
//ftpClient.retrieveFile(new String(ftpFile.getName().getBytes("GBK"), "ISO-8859-1"), outputStream);
// ftpclient自带方法 将图片转换成 inputStream
InputStream inputStream = ftpClient.retrieveFileStream(new String(ftpFile.getName().getBytes("GBK"), "ISO-8859-1"));
MultipartFile multipartFile = FileUtil.getMultipartFile(inputStream, filename);
fileList.add(multipartFile);
inputStream.close();
System.out.println("ftp获取图片成功。。。。");
}
}
}else {
InputStream inputStream = ftpClient.retrieveFileStream(new String(filename.getBytes("GBK"), "ISO-8859-1"));
MultipartFile multipartFile = FileUtil.getMultipartFile(inputStream, filename);//如果想直接上传的话 到这里就可以调用上传方法了
fileList.add(multipartFile);
inputStream.close();
System.out.println("ftp获取图片成功。。。。");
}
ftpClient.logout();
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
} catch (IOException ex) {
throw new RuntimeException(ex);
}finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException ioe) {
}
}
}
return fileList;
}
获取指定目录下的文件列表
public List<String> getFileNameList(String ftpDirPath) {
FTPClient ftpClient = connFtp();
List<String> list = new ArrayList();
try {
// 通过提供的文件路径获取FTPFile对象列表
FTPFile[] files = ftpClient.listFiles(ftpDirPath);
for (int i = 0; i < files.length; i++) {
FTPFile ftpFile = files[i];
if (ftpFile.isFile()) {
list.add(ftpFile.getName());
}
}
ftpClient.logout();
} catch (IOException e) {
log.error("错误" + e);
}finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException ioe) {
}
}
}
return list;
}
以下这个方法主要是判断,目录下是否有这个文件,用于某个文件主要判断是否需要录取文件流
/**
* 判断ftp服务器文件是否存在
*
* @param ftpClient
* @param path
* @return
* @throws IOException
*/
private static boolean existFile(FTPClient ftpClient, String path) throws IOException {
boolean flag = false;
FTPFile[] ftpFileArr = ftpClient.listFiles(path);
if (ftpFileArr.length > 0) {
flag = true;
}
return flag;
}
后续即是扩展内容,将文件流转换成MultipartFile ,剩下的就是正常上传业务逻辑了
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
/**
* 获取封装得MultipartFile
*
* @param inputStream inputStream
* @param fileName fileName
* @return MultipartFile
*/
public static MultipartFile getMultipartFile(InputStream inputStream, String fileName) {
FileItem fileItem = createFileItem(inputStream, fileName);
//CommonsMultipartFile是feign对multipartFile的封装,但是要FileItem类对象
return new CommonsMultipartFile(fileItem);
}
/**
* FileItem类对象创建
*
* @param inputStream inputStream
* @param fileName fileName
* @return FileItem
*/
public static FileItem createFileItem(InputStream inputStream, String fileName) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
String textFieldName = "file";
FileItem item = factory.createItem(textFieldName, MediaType.MULTIPART_FORM_DATA_VALUE, true, fileName);
int bytesRead = 0;
byte[] buffer = new byte[8192];
OutputStream os = null;
//使用输出流输出输入流的字节
try {
os = item.getOutputStream();
while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
inputStream.close();
} catch (IOException e) {
log.error("Stream copy exception", e);
throw new IllegalArgumentException("文件上传失败");
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
log.error("Stream close exception", e);
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error("Stream close exception", e);
}
}
}
return item;
}
总结起来,开发中主要遇到的问题:
1,文件命名不规范,导致拉取失败
2,文件中文乱码,导致找不到
有不懂的或理解不到的,可以留言,相互探讨
补充:特殊图片格式使用此方式有问题
可以采用下载后读取上传
public static void downLocal() throws IOException {
FTPClient ftpClient = connectFtpServer();
// 设置文件类型
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.changeWorkingDirectory(path);
// 设置要下载的文件名称
String fileName = "5_1663186150934798337.tif";
// 创建输出流,传入要下载的位置
FileOutputStream out = new FileOutputStream("E:\\www\\ffw\\images\\quanjing\\20230913\\" + "798337.jpg");
ftpClient.retrieveFile(fileName, out);
out.close();
System.out.println("下载成功");
}