配置FTP环境
1. 安装并启动 FTP 服务
安装VSFTPD
使用 apt-get
安装 [vsftpd]:
sudo apt-get install vsftpd -y
vsftpd
是在 Linux 上被广泛使用的 FTP 服务器,根据其官网介绍,它可能是 UNIX-like 系统下最安全和快速的 FTP 服务器软件。
启动VSFTPD
安装完成后 VSFTPD 会自动启动,通过 netstat
命令可以看到系统已经
sudo netstat -nltp | grep 21
如果没有启动,可以手动开启 VSFTPD 服务:
sudo systemctl start vsftpd.service # FTP协议默认使用21端口作为服务端口
2. 配置用户访问目录
新建用户主目录
sudo mkdir /home/uftp
执行完后,在这里 /home/uftp [?] 就能看到新建的文件夹 uftp 了。
创建登录欢迎文件 [?]:
sudo touch /home/uftp/welcome.txt
方便用户登录后可以看到欢迎信息,并且确定用户确实登录到了主目录上。
用户的主目录是用户通过 FTP 登录后看到的根目录
新建用户 uftp 并设置密码
sudo useradd -d /home/uftp -s /bin/bash uftp # 创建一个用户
sudo passwd uftp # 为用户设置密码
sudo rm /etc/pam.d/vsftpd # 删除掉 pam.d 中 vsftpd,因为该配置文件会导致使用用户名登录 ftp 失败:
限制该用户仅能通过 FTP 访问
sudo usermod -s /sbin/nologin uftp
修改 vsftpd 配置
sudo chmod a+w /etc/vsftpd.conf
# 修改vsftpd配置 /etc/vsftpd.conf
# 限制用户对主目录以外目录访问
chroot_local_user=YES
# 指定一个 userlist 存放允许访问 ftp 的用户列表
userlist_deny=NO
userlist_enable=YES
# 记录允许访问 ftp 用户列表
userlist_file=/etc/vsftpd.user_list
# 不配置可能导致莫名的530问题
seccomp_sandbox=NO
# 允许文件上传
write_enable=YES
# 使用utf8编码
utf8_filesystem=YES
新建文件 /etc/vsftpd.user_list
,用于存放允许访问 ftp 的用户:
sudo touch /etc/vsftpd.user_list
sudo chmod a+w /etc/vsftpd.user_list
# 修改 /etc/vsftpd.user_list
sudo touch /etc/vsftpd.user_list
sudo chmod a+w /etc/vsftpd.user_list
# 修改 /etc/vsftpd.user_list ,加入刚刚创建的用户:
uftp
设置主目录访问权限
sudo chmod a-w /home/uftp
sudo mkdir /home/uftp/public && sudo chmod 777 -R /home/uftp/public
sudo systemctl restart vsftpd.service
3. 访问方式
可以通过windows的资源管理器进行访问
ftp://106.52.107.51/
ftp://ftpuser:Password@<您的 CVM IP 地址>
java方式连接
FTP工具类:
package com.learning.ftp.util;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;
import org.yaml.snakeyaml.tokens.FlowEntryToken;
import sun.net.ftp.FtpClient;
import java.io.*;
/**
* @Author:siler
* @Date:2022/2/16 16:06
*/
public class FTPUtilsByApache {
Logger logger = Logger.getLogger(FTPUtilsByApache.class );
private String encoding = System.getProperty("file.encoding");
private FTPClient ftpClient =null;
private String url;
private int port;
private String username;
private String password;
/**
* @Date: 2022/2/16 16:08
* @Description: 默认为21端口
**/
public FTPUtilsByApache(String url,String username,String password){
this.url=url;
this.port=21;
this.username=username;
this.password=password;
}
public FTPUtilsByApache(String url,int port,String username,String password){
this.url=url;
this.port=port;
this.username=username;
this.password=password;
}
public FTPClient getFTPClient(){
int reply;
if(this.ftpClient == null || !this.ftpClient.isConnected()){
this.ftpClient=new FTPClient();
try{
this.ftpClient.connect(url,port);
boolean login = this.ftpClient.login(username, password);
if(login){
logger.info("FTP连接成功!");
}
// 设置文件传输类型为二进制传输
this.ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
this.ftpClient.setControlEncoding(encoding);
reply = ftpClient.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)){
ftpClient.disconnect();
return null;
}
return this.ftpClient;
}catch (IOException e){
e.printStackTrace();
logger.info("获取连接失败");
return null;
}
}else{
return this.ftpClient;
}
}
/**
* @Date: 2022/2/16 16:26
* @Description: 指定ftp文件名下载到本地
* @param remotePath ftp目录
* @param fileName 指定下载的文件
* @param localPath 本地目录
**/
public boolean downFile(String remotePath, String fileName,String localPath){
boolean result=false;
getFTPClient();
if(!isCreateFtpClient(this.ftpClient)){
return false;
}
try{
this.ftpClient.changeWorkingDirectory(remotePath);
FTPFile[] remoteFiles = this.ftpClient.listFiles();
for(FTPFile rf:remoteFiles){
if(rf.getName().equals(fileName)){
logger.info("获取到"+fileName+"文件");
// 创建本地存储路径
File lf = new File(localPath + File.separator + rf.getName());
FileOutputStream lfos = new FileOutputStream(lf);
// 通过文件检索系统,将文件写入流
this.ftpClient.retrieveFile(rf.getName(),lfos);
System.out.println("下载完毕");
lfos.close();
}
}
this.ftpClient.logout();
result=true;
}catch (IOException e){
e.printStackTrace();
return result;
}finally {
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch (Exception ee){
ee.printStackTrace();
}
}
}
return result;
}
/**
* @Date: 2022/2/16 16:42
* @Description: 下载所有文件到本地目录,不包含目录
* @param remotePath ftp目录
* @param localPath 本地目录
* @param prefix 前缀
* @param suffix 后缀
**/
public boolean downAllPathFile(String remotePath, String localPath,String prefix,String suffix){
boolean result=false;
if(prefix==null||prefix.trim().equals("")){
//return this.downAllPathFileSuffix(remotePath, localPath, suffix);
return result;
}else if(suffix==null||suffix.trim().equals("")){
//return this.downAllPathFilePrefix(remotePath, localPath, prefix);
return result;
}else{
getFTPClient();
if(!isCreateFtpClient(this.ftpClient)){
return false;
}
try{
this.ftpClient.changeWorkingDirectory(remotePath);
FTPFile[] remoteFiles = this.ftpClient.listFiles();
for(FTPFile rf:remoteFiles){
if(rf.isFile()&&rf.getName().contains(prefix)&&rf.getName().endsWith(suffix)){
logger.info("获取到"+rf.getName()+"文件");
File lf = new File(localPath + "/" + rf.getName());
FileOutputStream lfos = new FileOutputStream(lf);
// 通过文件检索系统,将文件写入流
this.ftpClient.retrieveFile(rf.getName(),lfos);
lfos.close();
}
}
this.ftpClient.logout();
result=true;
}catch (IOException e){
e.printStackTrace();
return result;
}finally {
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch (Exception ee){
ee.printStackTrace();
}
}
}
return result;
}
}
/**
* @Date: 2022/2/16 16:51
* @Description: 上传文件
**/
public boolean uploadFile(String remotePath, String filename, InputStream lin){
boolean result=false;
getFTPClient();
if(!this.isCreateFtpClient(this.ftpClient)){
return false;
}
try{
boolean change = ftpClient.changeWorkingDirectory(remotePath);
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
result = ftpClient.storeFile(new String(filename.getBytes(encoding),"iso-8859-1"), lin);
if(change){}
logger.info("上传完毕,结果为"+result);
lin.close();
ftpClient.logout();
}catch (Exception e){
e.printStackTrace();
}finally {
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch (Exception ee){
ee.printStackTrace();
}
}
}
return result;
}
/**
* @Date: 2022/2/16 16:56
* @Description: FTP文件上传
* @param remotePath
* @param localFilePath 完整的本地路径
**/
public boolean uploadFile(String remotePath,String localFilePath) {
File lf=new File(localFilePath);
try{
FileInputStream lfis = new FileInputStream(lf);
return uploadFile(remotePath,lf.getName(),lfis);
}catch (Exception e){
e.printStackTrace();
return false;
}
}
/**
* @Date: 2022/2/16 17:01
* @Description: 删除远程文件信息
**/
public boolean deleteFile(String filePath,String fileName){
getFTPClient();
boolean result = false;
if(isCreateFtpClient(this.ftpClient)){
try{
ftpClient.changeWorkingDirectory(filePath);
result = ftpClient.deleteFile(new String(fileName.getBytes(encoding),"iso-8859-1"));
}catch (IOException e){
e.printStackTrace();
return result;
}finally {
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch (Exception ee){
ee.printStackTrace();
}
}
}
}
return result;
}
/*
* @Date: 2022/2/16 16:30
* @Description: 是否创建ftp客户端
**/
public boolean isCreateFtpClient(FTPClient c){
if(c == null|| !c.isConnected()){
return false;
}else{
return true;
}
}
}
测试类:
public static void main(String[] args) throws FileNotFoundException {
String hostname = "106.52.107.51";
int port = 21;
String username = "ftpuser";
String password = "ZkAk_OgK";
String workingPath = "/pub";
String str = "E:\\game\\天气情况.log";
String loaclPath="E:\\SoftWare";
InputStream fileInputStream = new FileInputStream(new File(str));
String saveName = "天气情况.log";
String downName="天气情况.log";
FTPUtilsByApache utils = new FTPUtilsByApache(hostname,port,username,password);
utils.getFTPClient();
// 上传方法测试
//utils.uploadFile(workingPath,str);
// 下载方法测试
//System.out.println(utils.downFile(workingPath,downName,loaclPath));
// 删除方法测试
System.out.println(utils.deleteFile(workingPath,downName));
//System.out.println(FtpUtil.upload( hostname, port, username, password, workingPath, fileInputStream, saveName));
}