mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
add recursiveDownloadFolder
This commit is contained in:
parent
fb6d9d35fd
commit
fa936f4742
@ -3,9 +3,11 @@
|
|||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
## 5.3.5 (2020-05-10)
|
## 5.3.5 (2020-05-11)
|
||||||
|
|
||||||
### 新特性
|
### 新特性
|
||||||
|
* 【core 】 增加CollUtil.map方法
|
||||||
|
* 【extra 】 增加Sftp.lsEntries方法,Ftp和Sftp增加recursiveDownloadFolder(pr#121@Gitee)
|
||||||
### Bug修复
|
### Bug修复
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
|
@ -49,6 +49,7 @@ import java.util.concurrent.ArrayBlockingQueue;
|
|||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 集合相关工具类
|
* 集合相关工具类
|
||||||
@ -1170,16 +1171,31 @@ public class CollUtil {
|
|||||||
* @param ignoreNull 是否忽略空值
|
* @param ignoreNull 是否忽略空值
|
||||||
* @return 抽取后的新列表
|
* @return 抽取后的新列表
|
||||||
* @since 4.5.7
|
* @since 4.5.7
|
||||||
|
* @see #map(Iterable, Function, boolean)
|
||||||
*/
|
*/
|
||||||
public static List<Object> extract(Iterable<?> collection, Editor<Object> editor, boolean ignoreNull) {
|
public static List<Object> extract(Iterable<?> collection, Editor<Object> editor, boolean ignoreNull) {
|
||||||
final List<Object> fieldValueList = new ArrayList<>();
|
return map(collection, editor::edit, ignoreNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过func自定义一个规则,此规则将原集合中的元素转换成新的元素,生成新的列表返回<br>
|
||||||
|
* 例如提供的是一个Bean列表,通过Function接口实现获取某个字段值,返回这个字段值组成的新列表
|
||||||
|
*
|
||||||
|
* @param collection 原集合
|
||||||
|
* @param func 编辑函数
|
||||||
|
* @param ignoreNull 是否忽略空值
|
||||||
|
* @return 抽取后的新列表
|
||||||
|
* @since 5.3.5
|
||||||
|
*/
|
||||||
|
public static <T, R> List<R> map(Iterable<T> collection, Function<T, R> func, boolean ignoreNull) {
|
||||||
|
final List<R> fieldValueList = new ArrayList<>();
|
||||||
if (null == collection) {
|
if (null == collection) {
|
||||||
return fieldValueList;
|
return fieldValueList;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object value;
|
R value;
|
||||||
for (Object bean : collection) {
|
for (T bean : collection) {
|
||||||
value = editor.edit(bean);
|
value = func.apply(bean);
|
||||||
if (null == value && ignoreNull) {
|
if (null == value && ignoreNull) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1212,7 +1228,7 @@ public class CollUtil {
|
|||||||
* @since 4.5.7
|
* @since 4.5.7
|
||||||
*/
|
*/
|
||||||
public static List<Object> getFieldValues(Iterable<?> collection, final String fieldName, boolean ignoreNull) {
|
public static List<Object> getFieldValues(Iterable<?> collection, final String fieldName, boolean ignoreNull) {
|
||||||
return extract(collection, bean -> {
|
return map(collection, bean -> {
|
||||||
if (bean instanceof Map) {
|
if (bean instanceof Map) {
|
||||||
return ((Map<?, ?>) bean).get(fieldName);
|
return ((Map<?, ?>) bean).get(fieldName);
|
||||||
} else {
|
} else {
|
||||||
|
@ -567,7 +567,7 @@ public class FileUtil {
|
|||||||
* @return 最后修改时间
|
* @return 最后修改时间
|
||||||
*/
|
*/
|
||||||
public static Date lastModifiedTime(File file) {
|
public static Date lastModifiedTime(File file) {
|
||||||
if (!exist(file)) {
|
if (false == exist(file)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractFtp implements Closeable {
|
public abstract class AbstractFtp implements Closeable {
|
||||||
|
|
||||||
public static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8 ;
|
public static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8;
|
||||||
|
|
||||||
protected FtpConfig ftpConfig;
|
protected FtpConfig ftpConfig;
|
||||||
|
|
||||||
@ -28,15 +28,15 @@ public abstract class AbstractFtp implements Closeable {
|
|||||||
* @param config FTP配置
|
* @param config FTP配置
|
||||||
* @since 5.3.3
|
* @since 5.3.3
|
||||||
*/
|
*/
|
||||||
protected AbstractFtp(FtpConfig config){
|
protected AbstractFtp(FtpConfig config) {
|
||||||
this.ftpConfig = config;
|
this.ftpConfig = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 如果连接超时的话,重新进行连接
|
* 如果连接超时的话,重新进行连接
|
||||||
* @since 4.5.2
|
|
||||||
*
|
*
|
||||||
* @return this
|
* @return this
|
||||||
|
* @since 4.5.2
|
||||||
*/
|
*/
|
||||||
public abstract AbstractFtp reconnectIfTimeout();
|
public abstract AbstractFtp reconnectIfTimeout();
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ public abstract class AbstractFtp implements Closeable {
|
|||||||
final String[] dirs = StrUtil.trim(dir).split("[\\\\/]+");
|
final String[] dirs = StrUtil.trim(dir).split("[\\\\/]+");
|
||||||
|
|
||||||
final String now = pwd();
|
final String now = pwd();
|
||||||
if(dirs.length > 0 && StrUtil.isEmpty(dirs[0])) {
|
if (dirs.length > 0 && StrUtil.isEmpty(dirs[0])) {
|
||||||
//首位为空,表示以/开头
|
//首位为空,表示以/开头
|
||||||
this.cd(StrUtil.SLASH);
|
this.cd(StrUtil.SLASH);
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ public abstract class AbstractFtp implements Closeable {
|
|||||||
* 覆盖模式
|
* 覆盖模式
|
||||||
*
|
*
|
||||||
* @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
|
* @param destPath 服务端路径,可以为{@code null} 或者相对路径或绝对路径
|
||||||
* @param file 需要上传的文件
|
* @param file 需要上传的文件
|
||||||
* @return 是否成功
|
* @return 是否成功
|
||||||
*/
|
*/
|
||||||
public abstract boolean upload(String destPath, File file);
|
public abstract boolean upload(String destPath, File file);
|
||||||
@ -149,7 +149,7 @@ public abstract class AbstractFtp implements Closeable {
|
|||||||
/**
|
/**
|
||||||
* 下载文件
|
* 下载文件
|
||||||
*
|
*
|
||||||
* @param path 文件路径
|
* @param path 文件路径
|
||||||
* @param outFile 输出文件或目录
|
* @param outFile 输出文件或目录
|
||||||
*/
|
*/
|
||||||
public abstract void download(String path, File outFile);
|
public abstract void download(String path, File outFile);
|
||||||
@ -157,16 +157,18 @@ public abstract class AbstractFtp implements Closeable {
|
|||||||
/**
|
/**
|
||||||
* 递归下载FTP服务器上文件到本地(文件目录和服务器同步), 服务器上有新文件会覆盖本地文件
|
* 递归下载FTP服务器上文件到本地(文件目录和服务器同步), 服务器上有新文件会覆盖本地文件
|
||||||
*
|
*
|
||||||
* @param sourcePath ftp服务器目录
|
* @param sourcePath ftp服务器目录
|
||||||
* @param destinationPath 本地目录
|
* @param destDir 本地目录
|
||||||
|
* @since 5.3.5
|
||||||
*/
|
*/
|
||||||
public abstract void recursiveDownloadFolder(String sourcePath, String destinationPath) throws Exception;
|
public abstract void recursiveDownloadFolder(String sourcePath, File destDir);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------------- Private method start
|
// ---------------------------------------------------------------------------------------------------------------------------------------- Private method start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否包含指定字符串,忽略大小写
|
* 是否包含指定字符串,忽略大小写
|
||||||
*
|
*
|
||||||
* @param names 文件或目录名列表
|
* @param names 文件或目录名列表
|
||||||
* @param nameToFind 要查找的文件或目录名
|
* @param nameToFind 要查找的文件或目录名
|
||||||
* @return 是否包含
|
* @return 是否包含
|
||||||
*/
|
*/
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package cn.hutool.extra.ftp;
|
package cn.hutool.extra.ftp;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.ListUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.lang.Filter;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@ -158,7 +160,7 @@ public class Ftp extends AbstractFtp {
|
|||||||
try {
|
try {
|
||||||
// 连接ftp服务器
|
// 连接ftp服务器
|
||||||
client.connect(config.getHost(), config.getPort());
|
client.connect(config.getHost(), config.getPort());
|
||||||
client.setSoTimeout((int)config.getSoTimeout());
|
client.setSoTimeout((int) config.getSoTimeout());
|
||||||
// 登录ftp服务器
|
// 登录ftp服务器
|
||||||
client.login(config.getUser(), config.getPassword());
|
client.login(config.getUser(), config.getPassword());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -277,6 +279,34 @@ public class Ftp extends AbstractFtp {
|
|||||||
return fileNames;
|
return fileNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历某个目录下所有文件和目录,不会递归遍历<br>
|
||||||
|
* 此方法自动过滤"."和".."两种目录
|
||||||
|
*
|
||||||
|
* @param path 目录
|
||||||
|
* @param filter 过滤器,null表示不过滤,默认去掉"."和".."两种目录
|
||||||
|
* @return 文件或目录列表
|
||||||
|
* @since 5.3.5
|
||||||
|
*/
|
||||||
|
public List<FTPFile> lsFiles(String path, Filter<FTPFile> filter) {
|
||||||
|
final FTPFile[] ftpFiles = lsFiles(path);
|
||||||
|
if (ArrayUtil.isEmpty(ftpFiles)) {
|
||||||
|
return ListUtil.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<FTPFile> result = new ArrayList<>(ftpFiles.length - 2);
|
||||||
|
String fileName;
|
||||||
|
for (FTPFile ftpFile : ftpFiles) {
|
||||||
|
fileName = ftpFile.getName();
|
||||||
|
if (false == StrUtil.equals(".", fileName) && false == StrUtil.equals("..", fileName)) {
|
||||||
|
if (null == filter || filter.accept(ftpFile)) {
|
||||||
|
result.add(ftpFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 遍历某个目录下所有文件和目录,不会递归遍历
|
* 遍历某个目录下所有文件和目录,不会递归遍历
|
||||||
*
|
*
|
||||||
@ -479,28 +509,29 @@ public class Ftp extends AbstractFtp {
|
|||||||
/**
|
/**
|
||||||
* 递归下载FTP服务器上文件到本地(文件目录和服务器同步)
|
* 递归下载FTP服务器上文件到本地(文件目录和服务器同步)
|
||||||
*
|
*
|
||||||
* @param sourcePath ftp服务器目录
|
* @param sourcePath ftp服务器目录
|
||||||
* @param destinationPath 本地目录
|
* @param destDir 本地目录
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void recursiveDownloadFolder(String sourcePath, String destinationPath) {
|
public void recursiveDownloadFolder(String sourcePath, File destDir) {
|
||||||
String pathSeparator = "/";
|
String fileName;
|
||||||
FTPFile[] lsFiles = lsFiles(sourcePath);
|
String srcFile;
|
||||||
|
File destFile;
|
||||||
|
for (FTPFile ftpFile : lsFiles(sourcePath, null)) {
|
||||||
|
fileName = ftpFile.getName();
|
||||||
|
srcFile = StrUtil.format("{}/{}", sourcePath, fileName);
|
||||||
|
destFile = FileUtil.file(destDir, fileName);
|
||||||
|
|
||||||
for (FTPFile ftpFile : lsFiles) {
|
if (false == ftpFile.isDirectory()) {
|
||||||
String sourcePathPathFile = sourcePath + pathSeparator + ftpFile.getName();
|
|
||||||
String destinationPathFile = destinationPath + pathSeparator + ftpFile.getName();
|
|
||||||
|
|
||||||
if (!ftpFile.isDirectory()) {
|
|
||||||
// 本地不存在文件或者ftp上文件有修改则下载
|
// 本地不存在文件或者ftp上文件有修改则下载
|
||||||
if (!FileUtil.exist(destinationPathFile)
|
if (false == FileUtil.exist(destFile)
|
||||||
|| (ftpFile.getTimestamp().getTimeInMillis() > FileUtil.lastModifiedTime(destinationPathFile).getTime())) {
|
|| (ftpFile.getTimestamp().getTimeInMillis() > destFile.lastModified())) {
|
||||||
// Download file from source (source filename, destination filename).
|
download(srcFile, destFile);
|
||||||
download(sourcePathPathFile, FileUtil.file(destinationPathFile));
|
|
||||||
}
|
}
|
||||||
} else if (!(".".equals(ftpFile.getName()) || "..".equals(ftpFile.getName()))) {
|
} else {
|
||||||
FileUtil.mkdir(destinationPathFile);
|
// 服务端依旧是目录,继续递归
|
||||||
recursiveDownloadFolder(sourcePathPathFile, destinationPathFile);
|
FileUtil.mkdir(destFile);
|
||||||
|
recursiveDownloadFolder(srcFile, destFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package cn.hutool.extra.ssh;
|
package cn.hutool.extra.ssh;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.collection.ListUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.lang.Filter;
|
import cn.hutool.core.lang.Filter;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@ -37,6 +39,7 @@ public class Sftp extends AbstractFtp {
|
|||||||
private ChannelSftp channel;
|
private ChannelSftp channel;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------- Constructor start
|
// ---------------------------------------------------------------------------------------- Constructor start
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
*
|
*
|
||||||
@ -147,7 +150,7 @@ public class Sftp extends AbstractFtp {
|
|||||||
*/
|
*/
|
||||||
public void init(Session session, Charset charset) {
|
public void init(Session session, Charset charset) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
init(JschUtil.openSftp(session, (int)this.ftpConfig.getConnectionTimeout()), charset);
|
init(JschUtil.openSftp(session, (int) this.ftpConfig.getConnectionTimeout()), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -247,32 +250,62 @@ public class Sftp extends AbstractFtp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 遍历某个目录下所有文件或目录,不会递归遍历
|
* 遍历某个目录下所有文件或目录,不会递归遍历<br>
|
||||||
|
* 此方法自动过滤"."和".."两种目录
|
||||||
*
|
*
|
||||||
* @param path 遍历某个目录下所有文件或目录
|
* @param path 遍历某个目录下所有文件或目录
|
||||||
* @param filter 文件或目录过滤器,可以实现过滤器返回自己需要的文件或目录名列表
|
* @param filter 文件或目录过滤器,可以实现过滤器返回自己需要的文件或目录名列表
|
||||||
* @return 目录或文件名列表
|
* @return 目录或文件名列表
|
||||||
* @since 4.0.5
|
* @since 4.0.5
|
||||||
*/
|
*/
|
||||||
public List<String> ls(String path, final Filter<LsEntry> filter) {
|
public List<String> ls(String path, final Filter<LsEntry> filter) {
|
||||||
final List<String> fileNames = new ArrayList<>();
|
final List<LsEntry> entries = lsEntries(path, filter);
|
||||||
|
if (CollUtil.isEmpty(entries)) {
|
||||||
|
return ListUtil.empty();
|
||||||
|
}
|
||||||
|
return CollUtil.map(entries, LsEntry::getFilename, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历某个目录下所有文件或目录,生成LsEntry列表,不会递归遍历<br>
|
||||||
|
* 此方法自动过滤"."和".."两种目录
|
||||||
|
*
|
||||||
|
* @param path 遍历某个目录下所有文件或目录
|
||||||
|
* @return 目录或文件名列表
|
||||||
|
* @since 5.3.5
|
||||||
|
*/
|
||||||
|
public List<LsEntry> lsEntries(String path) {
|
||||||
|
return lsEntries(path, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历某个目录下所有文件或目录,生成LsEntry列表,不会递归遍历<br>
|
||||||
|
* 此方法自动过滤"."和".."两种目录
|
||||||
|
*
|
||||||
|
* @param path 遍历某个目录下所有文件或目录
|
||||||
|
* @param filter 文件或目录过滤器,可以实现过滤器返回自己需要的文件或目录名列表
|
||||||
|
* @return 目录或文件名列表
|
||||||
|
* @since 5.3.5
|
||||||
|
*/
|
||||||
|
public List<LsEntry> lsEntries(String path, Filter<LsEntry> filter) {
|
||||||
|
final List<LsEntry> entryList = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
channel.ls(path, entry -> {
|
channel.ls(path, entry -> {
|
||||||
String fileName = entry.getFilename();
|
final String fileName = entry.getFilename();
|
||||||
if (false == StrUtil.equals(".", fileName) && false == StrUtil.equals("..", fileName)) {
|
if (false == StrUtil.equals(".", fileName) && false == StrUtil.equals("..", fileName)) {
|
||||||
if (null == filter || filter.accept(entry)) {
|
if (null == filter || filter.accept(entry)) {
|
||||||
fileNames.add(entry.getFilename());
|
entryList.add(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return LsEntrySelector.CONTINUE;
|
return LsEntrySelector.CONTINUE;
|
||||||
});
|
});
|
||||||
} catch (SftpException e) {
|
} catch (SftpException e) {
|
||||||
if(false == StrUtil.startWithIgnoreCase(e.getMessage(), "No such file")){
|
if (false == StrUtil.startWithIgnoreCase(e.getMessage(), "No such file")) {
|
||||||
throw new JschRuntimeException(e);
|
throw new JschRuntimeException(e);
|
||||||
}
|
}
|
||||||
// 文件不存在忽略
|
// 文件不存在忽略
|
||||||
}
|
}
|
||||||
return fileNames;
|
return entryList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -375,7 +408,7 @@ public class Sftp extends AbstractFtp {
|
|||||||
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。覆盖模式
|
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。覆盖模式
|
||||||
*
|
*
|
||||||
* @param srcFilePath 本地文件路径
|
* @param srcFilePath 本地文件路径
|
||||||
* @param destPath 目标路径,
|
* @param destPath 目标路径,
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public Sftp put(String srcFilePath, String destPath) {
|
public Sftp put(String srcFilePath, String destPath) {
|
||||||
@ -386,8 +419,8 @@ public class Sftp extends AbstractFtp {
|
|||||||
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。
|
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。
|
||||||
*
|
*
|
||||||
* @param srcFilePath 本地文件路径
|
* @param srcFilePath 本地文件路径
|
||||||
* @param destPath 目标路径,
|
* @param destPath 目标路径,
|
||||||
* @param mode {@link Mode} 模式
|
* @param mode {@link Mode} 模式
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public Sftp put(String srcFilePath, String destPath, Mode mode) {
|
public Sftp put(String srcFilePath, String destPath, Mode mode) {
|
||||||
@ -398,9 +431,9 @@ public class Sftp extends AbstractFtp {
|
|||||||
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。
|
* 将本地文件上传到目标服务器,目标文件名为destPath,若destPath为目录,则目标文件名将与srcFilePath文件名相同。
|
||||||
*
|
*
|
||||||
* @param srcFilePath 本地文件路径
|
* @param srcFilePath 本地文件路径
|
||||||
* @param destPath 目标路径,
|
* @param destPath 目标路径,
|
||||||
* @param monitor 上传进度监控,通过实现此接口完成进度显示
|
* @param monitor 上传进度监控,通过实现此接口完成进度显示
|
||||||
* @param mode {@link Mode} 模式
|
* @param mode {@link Mode} 模式
|
||||||
* @return this
|
* @return this
|
||||||
* @since 4.6.5
|
* @since 4.6.5
|
||||||
*/
|
*/
|
||||||
@ -421,30 +454,29 @@ public class Sftp extends AbstractFtp {
|
|||||||
/**
|
/**
|
||||||
* 递归下载FTP服务器上文件到本地(文件目录和服务器同步)
|
* 递归下载FTP服务器上文件到本地(文件目录和服务器同步)
|
||||||
*
|
*
|
||||||
* @param sourcePath ftp服务器目录
|
* @param sourcePath ftp服务器目录,必须为目录
|
||||||
* @param destinationPath 本地目录
|
* @param destDir 本地目录
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void recursiveDownloadFolder(String sourcePath, String destinationPath) throws Exception {
|
public void recursiveDownloadFolder(String sourcePath, File destDir) throws JschRuntimeException {
|
||||||
String pathSeparator = "/";
|
String fileName;
|
||||||
Vector<ChannelSftp.LsEntry> fileAndFolderList = channel.ls(sourcePath);
|
String srcFile;
|
||||||
|
File destFile;
|
||||||
|
for (LsEntry item : lsEntries(sourcePath)) {
|
||||||
|
fileName = item.getFilename();
|
||||||
|
srcFile = StrUtil.format("{}/{}", sourcePath, fileName);
|
||||||
|
destFile = FileUtil.file(destDir, fileName);
|
||||||
|
|
||||||
//Iterate through list of folder content
|
if (false == item.getAttrs().isDir()) {
|
||||||
for (ChannelSftp.LsEntry item : fileAndFolderList) {
|
|
||||||
|
|
||||||
String sourcePathPathFile = sourcePath + pathSeparator + item.getFilename();
|
|
||||||
String destinationPathFile = destinationPath + pathSeparator + item.getFilename();
|
|
||||||
|
|
||||||
if (!item.getAttrs().isDir()) {
|
|
||||||
// 本地不存在文件或者ftp上文件有修改则下载
|
// 本地不存在文件或者ftp上文件有修改则下载
|
||||||
if (!FileUtil.exist(destinationPathFile)
|
if (false == FileUtil.exist(destFile)
|
||||||
|| (item.getAttrs().getMTime() > (FileUtil.lastModifiedTime(destinationPathFile).getTime() / 1000))) {
|
|| (item.getAttrs().getMTime() > (destFile.lastModified() / 1000))) {
|
||||||
// Download file from source (source filename, destination filename).
|
download(srcFile, destFile);
|
||||||
channel.get(sourcePathPathFile, destinationPathFile);
|
|
||||||
}
|
}
|
||||||
} else if (!(".".equals(item.getFilename()) || "..".equals(item.getFilename()))) {
|
} else {
|
||||||
FileUtil.mkdir(destinationPathFile);
|
// 服务端依旧是目录,继续递归
|
||||||
recursiveDownloadFolder(sourcePathPathFile, destinationPathFile);
|
FileUtil.mkdir(destFile);
|
||||||
|
recursiveDownloadFolder(srcFile, destFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +485,7 @@ public class Sftp extends AbstractFtp {
|
|||||||
/**
|
/**
|
||||||
* 获取远程文件
|
* 获取远程文件
|
||||||
*
|
*
|
||||||
* @param src 远程文件路径
|
* @param src 远程文件路径
|
||||||
* @param dest 目标文件路径
|
* @param dest 目标文件路径
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
@ -485,14 +517,19 @@ public class Sftp extends AbstractFtp {
|
|||||||
* JSch支持的三种文件传输模式
|
* JSch支持的三种文件传输模式
|
||||||
*
|
*
|
||||||
* @author looly
|
* @author looly
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public enum Mode {
|
public enum Mode {
|
||||||
/** 完全覆盖模式,这是JSch的默认文件传输模式,即如果目标文件已经存在,传输的文件将完全覆盖目标文件,产生新的文件。 */
|
/**
|
||||||
|
* 完全覆盖模式,这是JSch的默认文件传输模式,即如果目标文件已经存在,传输的文件将完全覆盖目标文件,产生新的文件。
|
||||||
|
*/
|
||||||
OVERWRITE,
|
OVERWRITE,
|
||||||
/** 恢复模式,如果文件已经传输一部分,这时由于网络或其他任何原因导致文件传输中断,如果下一次传输相同的文件,则会从上一次中断的地方续传。 */
|
/**
|
||||||
|
* 恢复模式,如果文件已经传输一部分,这时由于网络或其他任何原因导致文件传输中断,如果下一次传输相同的文件,则会从上一次中断的地方续传。
|
||||||
|
*/
|
||||||
RESUME,
|
RESUME,
|
||||||
/** 追加模式,如果目标文件已存在,传输的文件将在目标文件后追加。 */
|
/**
|
||||||
|
* 追加模式,如果目标文件已存在,传输的文件将在目标文件后追加。
|
||||||
|
*/
|
||||||
APPEND
|
APPEND
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
package cn.hutool.extra.ftp;
|
package cn.hutool.extra.ftp;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import cn.hutool.extra.ssh.Sftp;
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.lang.Console;
|
import cn.hutool.core.lang.Console;
|
||||||
|
import cn.hutool.extra.ssh.Sftp;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class FtpTest {
|
public class FtpTest {
|
||||||
|
|
||||||
@ -63,21 +62,21 @@ public class FtpTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
public void recursiveDownloadFolder() throws Exception {
|
public void recursiveDownloadFolder() {
|
||||||
Ftp ftp = new Ftp("looly.centos");
|
Ftp ftp = new Ftp("looly.centos");
|
||||||
ftp.recursiveDownloadFolder("/","d:/test/download");
|
ftp.recursiveDownloadFolder("/",FileUtil.file("d:/test/download"));
|
||||||
|
|
||||||
IoUtil.close(ftp);
|
IoUtil.close(ftp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
public void recursiveDownloadFolderSftp() throws Exception {
|
public void recursiveDownloadFolderSftp() {
|
||||||
Sftp ftp = new Sftp("127.0.0.1", 22, "test", "test");
|
Sftp ftp = new Sftp("127.0.0.1", 22, "test", "test");
|
||||||
|
|
||||||
ftp.cd("/file/aaa");
|
ftp.cd("/file/aaa");
|
||||||
Console.log(ftp.pwd());
|
Console.log(ftp.pwd());
|
||||||
ftp.recursiveDownloadFolder("/","d:/test/download");
|
ftp.recursiveDownloadFolder("/",FileUtil.file("d:/test/download"));
|
||||||
|
|
||||||
IoUtil.close(ftp);
|
IoUtil.close(ftp);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user