org.dromara.hutool.extra.ftp.AbstractFtp Maven / Gradle / Ivy
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.extra.ftp;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.io.file.FileNameUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.io.File;
import java.util.List;
/**
* 抽象FTP类,用于定义通用的FTP方法
*
* @author looly
* @since 4.1.14
*/
public abstract class AbstractFtp implements Ftp {
protected FtpConfig ftpConfig;
@Override
public FtpConfig getConfig() {
return this.ftpConfig;
}
/**
* 构造
*
* @param config FTP配置
* @since 5.3.3
*/
protected AbstractFtp(final FtpConfig config) {
this.ftpConfig = config;
}
@Override
public boolean exist(final String path) {
if (StrUtil.isBlank(path)) {
return false;
}
// 目录验证
if (isDir(path)) {
return true;
}
if (CharUtil.isFileSeparator(path.charAt(path.length() - 1))) {
return false;
}
final String fileName = FileNameUtil.getName(path);
if (StrUtil.DOT.equals(fileName) || StrUtil.DOUBLE_DOT.equals(fileName)) {
return false;
}
// 文件验证
final String dir = StrUtil.defaultIfEmpty(StrUtil.removeSuffix(path, fileName), StrUtil.DOT);
// issue#I7CSQ9 检查父目录为目录且是否存在
if (!isDir(dir)) {
return false;
}
final List names;
try {
names = ls(dir);
} catch (final FtpException ignore) {
return false;
}
return containsIgnoreCase(names, fileName);
}
@Override
public void mkDirs(final String dir) {
final String[] dirs = StrUtil.trim(dir).split("[\\\\/]+");
final String now = pwd();
if (dirs.length > 0 && StrUtil.isEmpty(dirs[0])) {
//首位为空,表示以/开头
this.cd(StrUtil.SLASH);
}
for (final String s : dirs) {
if (StrUtil.isNotEmpty(s)) {
boolean exist = true;
try {
if (!cd(s)) {
exist = false;
}
} catch (final FtpException e) {
exist = false;
}
if (!exist) {
//目录不存在时创建
mkdir(s);
cd(s);
}
}
}
// 切换回工作目录
cd(now);
}
/**
* 下载文件-避免未完成的文件
* 来自:https://gitee.com/dromara/hutool/pulls/407
* 此方法原理是先在目标文件同级目录下创建临时文件,下载之,等下载完毕后重命名,避免因下载错误导致的文件不完整。
*
* @param path 文件路径
* @param outFile 输出文件或目录
* @param tempFileSuffix 临时文件后缀,默认".temp"
* @since 5.7.12
*/
public void download(final String path, File outFile, String tempFileSuffix) {
if (StrUtil.isBlank(tempFileSuffix)) {
tempFileSuffix = ".temp";
} else {
tempFileSuffix = StrUtil.addPrefixIfNot(tempFileSuffix, StrUtil.DOT);
}
// 目标文件真实名称
final String fileName = outFile.isDirectory() ? FileNameUtil.getName(path) : outFile.getName();
// 临时文件名称
final String tempFileName = fileName + tempFileSuffix;
// 临时文件
outFile = new File(outFile.isDirectory() ? outFile : outFile.getParentFile(), tempFileName);
try {
download(path, outFile);
// 重命名下载好的临时文件
FileUtil.rename(outFile, fileName, true);
} catch (final Throwable e) {
// 异常则删除临时文件
FileUtil.del(outFile);
throw new FtpException(e);
}
}
// ---------------------------------------------------------------------------------------------------------------------------------------- Private method start
/**
* 是否包含指定字符串,忽略大小写
*
* @param names 文件或目录名列表
* @param nameToFind 要查找的文件或目录名
* @return 是否包含
*/
private static boolean containsIgnoreCase(final List names, final String nameToFind) {
if (StrUtil.isEmpty(nameToFind)) {
return false;
}
return CollUtil.contains(names, nameToFind::equalsIgnoreCase);
}
// ---------------------------------------------------------------------------------------------------------------------------------------- Private method end
}