项目中开始使用http协议进行传输文件,但是终端提出传输的字节超过限度,要使用FTP文件服务器进行断点续传,每次1k的进行传输. 老大让我在开发环境中搭建vsftp服务器,一起没操作过,现在记录下来留做以后的回顾学习;
vsftp简介
CentOS6.5安装vsftp
1.检测是否安装了vsftp
我是安装过的, 命令下方返回的是我的vsftp版本
[root@dev04 ~]# rpm -qa |grep vsftpd vsftpd-2.2.2-14.el6.x86_64
检测到安装过后如果想卸载执行:
rpm -e vsftpd
再执行
rpm -qa |grep vsftpd
查看卸载是否成功,如果成功会返回卸载的vsftp的版本
2.安装vsftp
yum install vsftpd* -y
3.设置开机自启vsftp ftp服务
chkconfig vsftpd on
4.启动ftp服务
[root@dev04 vsftpd]# service vsftpd start
关闭服务:
[root@dev04 vsftpd]# service vsftpd stop
重启服务:
[root@dev04 vsftpd]# service vsftpd restart
5.配置vsftp的配置文件vsftpd.conf
在 /etc/vsftpd目录下有三个文件和一个执行命令?
-rw——- 1 root root 125 Jul 24 2015 ftpusers -rw——- 1 root root 371 Apr 6 14:11 user_list -rw——- 1 root root 4737 Apr 1 15:51 vsftpd.conf -rwxr–r– 1 root root 338 Jul 24 2015 vsftpd_conf_migrate.sh
[root@dev04 vsftpd]# cp vsftpd.conf vsftpd.conf.bak
再进行编辑修改配置文件
[root@dev04 vsftpd]# vim /etc/vsftpd/vsftpd.conf
主要的就是匿名用户的访问权限和 新增本地用户设置访问权限
anonymous_enable=YES // 支持匿名登录,如果改为NO不支持匿名登录
write_enable=YES //支持读
anon_upload_enable=YES //支持匿名改写
anon_mkdir_write_enable=YES //支持匿名用户创建子目录
6.创建用户ftpuser,指定目录/home/ftpuser,禁止SSH登录权限
useradd -d /home/ftpuser -g ftp -s /sbin/nologin ftpuser
给帐号设置密码
passwd ftpuer
注意: 在设置密码时会提示什么密码过于简单,或者密码为单词词组等等,不用管,它已经进行设置了,要确认两次输入的密码都相同;输入两次密码后出现successful…..就代表设置密码成功了;
创建用户时遇到的问题:
useradd -d /var/ftp -g ftp -s /sbin/nologin anon
在使用java进行上传文件时发现anon用户不能连接上该目录,查资料说是没有对目录进行设置权限
注意的事项是的:
1、pub目录的权限不能全开,全开会报错,chmod 755 -R pub
2、但是这样也会带来一个问题,当匿名用户登录后,在pub下的newftp目录下想上传一个文件,会报错,因为匿名用户(ftp)无法在该目录下(该目录属于root用户)创建一个新文件的,因为该目录下他没有权限,所以要加入其他用户(o)的写权限,chmod o+w /var/ftp/pub/.
现在权限变为:
drwxr-xrwx 2 root root 4096 06-20 16:55 pub
其实就是757的权限,此时匿名用户(ftp)就可以在该目录下上传文件了。
最后重启服务: service vsftpd restart
附上MultipartFile使用ftp上传文件
1.maven项目中添加pom文件
-
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
-
<dependency>
-
<groupId>commons-net
</groupId>
-
<artifactId>commons-net
</artifactId>
-
<version>3.6
</version>
-
</dependency>
2.ftp配置文件 ftp_client.properties
#公网IP映射地址: 218.205.115.XXX 2121
ftp_public_network_add = 218.205.115.XXX
匿名登录上传目录 /var/ftp/pub
remoteFile_addr = /var/ftp/pub/
3.自定义配置文件的pojo类,提高代码扩展性
- <code class=“language-html”>@Component
- public class FTPConfig {
- / FTP服务器IP地址 /
- @Value(“#{configProperties[‘ftp_host’]}”)
- private String fTPhost = “localhost”;
- / FTP服务器端口 /
- @Value(“#{configProperties[‘ftp_port’]}”)
- private int ftpPort = 21;
- / FTP服务器用户名 /
- @Value(“#{configProperties[‘ftp_user_name’]}”)
- private String ftpUserName;
- / FTP用户密码 /
- @Value(“#{configProperties[‘ftp_user_pwd’]}”)
- private String ftpUserPasswd;
- / 用户远程上传文件存储目录 /
- @Value(“#{configProperties[‘remoteFile_addr’]}”)
- private String remoteFileAddr;
- / FTP公网映射地址 /
- @Value(“#{configProperties[‘ftp_public_network_add’]}”)
- private String ftpNetAdd;
- / FTP公网端口 /
- @Value(“#{configProperties[‘ftp_public_network_port’]}”)
- private int ftpNetPort = 2121;</code>
-
@Component
-
public class FTPConfig {
-
-
/ FTP服务器IP地址 /
-
@Value("#{configProperties['ftp_host']}")
-
private String fTPhost = "localhost";
-
-
/
* FTP服务器端口 /
-
@Value("#{configProperties['ftp_port']}")
-
private int ftpPort = 21;
-
-
/
* FTP服务器用户名 /
-
@Value("#{configProperties['ftp_user_name']}")
-
private String ftpUserName;
-
-
/
* FTP用户密码 /
-
@Value("#{configProperties['ftp_user_pwd']}")
-
private String ftpUserPasswd;
-
-
/
* 用户远程上传文件存储目录 /
-
@Value("#{configProperties['remoteFile_addr']}")
-
private String remoteFileAddr;
-
-
/
* FTP公网映射地址 /
-
@Value("#{configProperties['ftp_public_network_add']}")
-
private String ftpNetAdd;
-
-
/
* FTP公网端口 /
-
@Value("#{configProperties['ftp_public_network_port']}")
-
private int ftpNetPort = 2121;
}
4.FTP上传下载的工具类FTPFileManager
-
/**
-
* @Type ftpClientFileManager.java
-
* @Desc
-
* @author 123
-
* @date 2017年3月31日 下午2:50:58
-
* @version
-
*/
-
@Service
-
public
class FTPFileManager {
-
-
private
static
final Logger logger = LoggerFactory.getLogger(FTPFileManager.class);
-
-
private FTPClient ftpClient =
new FTPClient();
-
-
/** 路径分隔符 */
-
private
static
final String SEPARATOR =
“/”;
-
-
/** FTP访问路径前缀 */
-
private
static
final String FTP_PREFIX =
“ftp://”;
-
-
@Autowired
-
private FTPConfig config;
-
-
/**
-
* @Title: upload
-
*
-
* @Description: 文件上传
-
*
-
* @param uploadFile
-
* MultipartFile
-
* @return
-
* 返回保存路径 + 文件名
-
* @throws Exception
-
*
-
*/
-
public String upload(MultipartFile uploadFile) throws Exception {
-
-
ftpClient =
new FTPClient();
-
ftpClient.connect(config.getfTPhost(), config.getFtpPort());
-
-
ftpClient.login(config.getFtpUserName(), config.getFtpUserPasswd());
-
//设置ftp字节流
-
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
-
int reply;
-
reply = ftpClient.getReplyCode();
-
if (!FTPReply.isPositiveCompletion(reply)) {
-
ftpClient.disconnect();
-
return
null;
-
}
-
ftpClient.enterLocalPassiveMode();
-
String basePath = config.getRemoteFileAddr();
-
ftpClient.changeWorkingDirectory(basePath);
-
-
//为当天日期文件创建追加目录
-
Date today =
new Date();
-
SimpleDateFormat sdf =
new SimpleDateFormat(
“yyyy/MM/dd”);
-
String appendFile = sdf.format(today);
-
//切换到上传目录
-
if (!ftpClient.changeWorkingDirectory(basePath + appendFile)) {
-
//如果目录不存在创建目录
-
String[] dirs = appendFile.split(SEPARATOR);
-
String tempTargetPath = basePath;
-
for (String dir : dirs) {
-
if (
null == dir ||
“”.equals(dir))
-
continue;
-
tempTargetPath += SEPARATOR + dir;
-
if (!ftpClient.changeWorkingDirectory(tempTargetPath)) {
-
if (!ftpClient.makeDirectory(tempTargetPath)) {
-
logger.error(
“ftp文件目录创建失败!”);
-
return
null;
-
}
else {
-
ftpClient.changeWorkingDirectory(tempTargetPath);
-
}
-
}
-
}
-
}
-
-
String fileName =
new String(uploadFile.getOriginalFilename().getBytes(
“utf-8”),
-
“iso-8859-1”);
-
/**
-
* 避免文件过多后出现重名,设置30位随机数为文件名称
-
*/
-
// 获取文件扩展名 形如: .txt
-
String fileExt = fileName.substring(fileName.lastIndexOf(
“.”));
-
String newFileName = RandomUtils.randomAlphanumericStrictly(
30) + fileExt;
-
-
InputStream is = uploadFile.getInputStream();
-
if (!ftpClient.storeFile(newFileName, is)) {
-
logger.error(
“文件{}存储过程出错”, fileName);
-
return
null;
-
}
-
is.close();
-
ftpClient.disconnect();
-
/* String finalFile = basePath + SEPARATOR + appendFile + SEPARATOR + fileName;*/
-
//直接存储为匿名用户可直接访问下载的地址
-
String finalFile = FTP_PREFIX + config.getFtpNetAdd() +
“:” + config.getFtpNetPort()
-
+ SEPARATOR +
“pub” + SEPARATOR + appendFile + SEPARATOR + newFileName;
-
logger.info(
“文件上传FTP服务器成功, 访问文件路径为 : “ + finalFile);
-
return finalFile;
-
}
-
-
/**
-
* 从FTP服务器上下载文件
-
* @param remote 远程文件路径
-
* @param local 本地文件路径
-
* @return 是否成功
-
* @throws Exception
-
*/
-
public boolean download(String remote, String local) throws Exception {
-
ftpClient =
new FTPClient();
-
ftpClient.connect(config.getfTPhost(), config.getFtpPort());
-
ftpClient.login(config.getFtpUserName(), config.getFtpUserPasswd());
-
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
-
int reply;
-
reply = ftpClient.getReplyCode();
-
if (!FTPReply.isPositiveCompletion(reply)) {
-
ftpClient.disconnect();
-
return
false;
-
}
-
-
ftpClient.enterLocalPassiveMode();
-
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
-
boolean result;
-
File f =
new File(local);
-
FTPFile[] files = ftpClient.listFiles(remote);
-
if (files.length !=
1) {
-
System.out.println(
“远程文件不唯一”);
-
ftpClient.disconnect();
-
return
false;
-
}
-
long lRemoteSize = files[
0].getSize();
-
if (f.exists()) {
-
OutputStream out =
new FileOutputStream(f,
true);
-
System.out.println(
“本地文件大小为:” + f.length());
-
if (f.length() >= lRemoteSize) {
-
logger.error(
“本地文件大小大于远程文件大小,下载中止”);
-
out.close();
-
ftpClient.disconnect();
-
return
false;
-
}
-
ftpClient.setRestartOffset(f.length());
-
result = ftpClient.retrieveFile(remote, out);
-
out.close();
-
}
else {
-
OutputStream out =
new FileOutputStream(f);
-
result = ftpClient.retrieveFile(remote, out);
-
out.close();
-
}
-
ftpClient.disconnect();
-
return result;
-
}
-
-
}
-
-
/**
-
* Revision history
-
* ————————————————————————-
-
*
-
* Date Author Note
-
* ————————————————————————-
-
* 2017年3月31日 123 creat
-
*/
此时,用户可以通过公网映射的IP进行访问, 类似 ftp://218.205.115.XXXX:2121/pub/2017/04/06/4cn91c2dRffmQ8diQ4mvDRo5m2lWtr.txt
由于项目中没使用到文件下载,我只在本地进行了简单的下载centOS中FTP文件测试.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
支持断点续传的上传方法
-
/*
-
上传文件到FTP服务器,支持断点续传
-
* @param local 本地文件名称,绝对路径
-
* @param remote 远程文件路径,使用/home/directory1/subdirectory/file.ext 按照Linux上的路径指定方式,支持多级目录嵌套,支持递归创建不存在的目录结构
-
* @return 上传结果
-
* @throws IOException
-
*/
-
public String upload(String local, String remote) throws IOException {
-
//设置PassiveMode传输
-
ftpClient.enterLocalPassiveMode();
-
//设置以二进制流的方式传输
-
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
-
String uploadStatus;
-
//对远程目录的处理
-
String remoteFileName = remote;
-
if (remote.contains(
"/")) {
-
remoteFileName = remote.substring(remote.lastIndexOf(
"/") +
1);
-
String directory = remote.substring(
0, remote.lastIndexOf(
"/") +
1);
-
if (!directory.equalsIgnoreCase(
"/") && !ftpClient.changeWorkingDirectory(directory)) {
-
//如果远程目录不存在,则递归创建远程服务器目录
-
int start =
0;
-
int end =
0;
-
if (directory.startsWith(
"/")) {
-
start =
1;
-
}
else {
-
start =
0;
-
}
-
end = directory.indexOf(
"/", start);
-
while (
true) {
-
String subDirectory = remote.substring(start, end);
-
if (!ftpClient.changeWorkingDirectory(subDirectory)) {
-
if (ftpClient.makeDirectory(subDirectory)) {
-
ftpClient.changeWorkingDirectory(subDirectory);
-
}
else {
-
System.out.println(
"创建目录失败");
-
return UploadStatus.Create_Directory_Fail;
-
}
-
}
-
-
start = end +
1;
-
end = directory.indexOf(
"/", start);
-
-
//检查所有目录是否创建完毕
-
if (end <= start) {
-
break;
-
}
-
}
-
}
-
}
-
-
//检查远程是否存在文件
-
FTPFile[] files = ftpClient.listFiles(remoteFileName);
-
if (files.length ==
1) {
-
long remoteSize = files[
0].getSize();
-
File f =
new File(local);
-
long localSize = f.length();
-
if (remoteSize == localSize) {
-
return UploadStatus.File_Exits;
-
}
else
if (remoteSize > localSize) {
-
return UploadStatus.Remote_Bigger_Local;
-
}
-
-
//尝试移动文件内读取指针,实现断点续传
-
InputStream is =
new FileInputStream(f);
-
if (is.skip(remoteSize) == remoteSize) {
-
//设置文件开始
-
ftpClient.setRestartOffset(remoteSize);
-
if (ftpClient.storeFile(remote, is)) {
-
is.close();
-
return UploadStatus.Upload_From_Break_Success;
-
}
-
-
}
-
-
//如果断点续传没有成功,则删除服务器上文件,重新上传
-
if (!ftpClient.deleteFile(remoteFileName)) {
-
return UploadStatus.Delete_Remote_Faild;
-
}
-
is =
new FileInputStream(f);
-
if (ftpClient.storeFile(remote, is)) {
-
uploadStatus = UploadStatus.Upload_New_File_Success;
-
}
else {
-
uploadStatus = UploadStatus.Upload_New_File_Failed;
-
}
-
is.close();
-
}
else {
-
InputStream is =
new FileInputStream(local);
-
if (ftpClient.storeFile(remoteFileName, is)) {
-
uploadStatus = UploadStatus.Upload_New_File_Success;
-
}
else {
-
uploadStatus = UploadStatus.Upload_New_File_Failed;
-
}
-
is.close();
-
}
-
return uploadStatus;
-
}