linux 配置ftp服务
需求:定时远程上传文件,windows->linux
linux是一个云服务器,centos7
1:安装vsftpd
yum install vsftpd
2:设置开机启动服务
chkconfig vsftpd on
3:启动服务
service vsftpd start
4:防火墙端口打开
打开/etc/sysconfig/iptables文件
vi /etc/sysconfig/iptables
在REJECT行之前添加如下代码
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 21 -j ACCEPT
保存和关闭文件,重启防火墙
service iptables restart
5:配置vsftpd 服务器
vi /etc/vsftpd/vsftpd.conf
将匿名登录关闭 anonymous_enable=NO
chroot_list_enable=YES //限制访问自身目录
# (default follows)
chroot_list_file=/etc/vsftpd/vsftpd.chroot_list
编辑 vsftpd.chroot_list文件,将受限制的用户添加进去,每个用户名一行,(但实际上加了这个会很麻烦,所以没加),比如出现 500 OOPS: vsftpd: refusing to run with writable root inside chroot()
参考这个link:https://zhidao.baidu.com/question/1732079113433285347.html
6:添加ftp用户
useradd -d /home/test test
passwd oneuser
如果加错了,可以删掉这个用户
userdel test
7:修改文件夹所有者
chown test /home/test -R
如果还是不好使,改一下权限
chmod -R 777 /home/test
8:最后,别忘了重启服务
service vsftpd restart
9:查看用户默认路径: cat /etc/passwd
通过java的FTPClient去连接时会出现各种错误,首先,用户名和密码,端口别搞错了,FTPClient的jar包可以选最高的版本
网上有FTPutil的代码,我也是拿来主义了,但是发现有bug,下面是自己测试过的代码,传单个文件,如果要传文件夹的话也很简单。
补充:如果出现下载文件ftpClient.listFiles()为null的错误,用以下方法解决
执行ftpClient.listFiles()前加上一句:
ftpClient.enterLocalPassiveMode();
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; 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; public class FtpUtils { //ftp服务器地址 public String hostname = "XXXX"; //ftp服务器端口号默认为21 public Integer port = 21 ; //ftp登录账号 public String username = "XXX"; //ftp登录密码 public String password = "XXX"; public FTPClient ftpClient = null; /** * 初始化ftp服务器 */ public void initFtpClient() { ftpClient = new FTPClient(); ftpClient.setControlEncoding("utf-8"); try { System.out.println("connecting...ftp服务器:"+this.hostname+":"+this.port); ftpClient.connect(hostname, port); //连接ftp服务器 ftpClient.login(username, password); //登录ftp服务器 int replyCode = ftpClient.getReplyCode(); //是否成功登录服务器 if(!FTPReply.isPositiveCompletion(replyCode)){ System.out.println("connect failed...ftp服务器:"+this.hostname+":"+this.port); }else{ System.out.println("connect successfu...ftp服务器:"+this.hostname+":"+this.port); } }catch (MalformedURLException e) { e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); } } /** * 上传文件 * @param pathname ftp服务保存地址 * @param fileName 上传到ftp的文件名 * @param originfilename 待上传文件的名称(绝对地址) * * @return */ public boolean uploadFile( String pathname, String fileName,String originfilename){ boolean flag = false; InputStream inputStream = null; try{ System.out.println("开始上传文件"); inputStream = new FileInputStream(new File(originfilename)); initFtpClient(); ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE); ftpClient.setDataTimeout(60000); //设置传输超时时间为60秒 ftpClient.setConnectTimeout(60000); //连接超时为60秒 ftpClient.storeFile(fileName, inputStream); inputStream.close(); ftpClient.logout(); flag = true; System.out.println("上传文件成功"); }catch (Exception e) { System.out.println("上传文件失败"); e.printStackTrace(); }finally{ if(ftpClient.isConnected()){ try{ ftpClient.disconnect(); }catch(IOException e){ e.printStackTrace(); } } if(null != inputStream){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return true; } /** * 上传文件 * @param pathname ftp服务保存地址 * @param fileName 上传到ftp的文件名 * @param inputStream 输入文件流 * @return */ public boolean uploadFile( String pathname, String fileName,InputStream inputStream){ boolean flag = false; try{ System.out.println("开始上传文件"); initFtpClient(); ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE); CreateDirecroty(pathname); ftpClient.makeDirectory(pathname); ftpClient.changeWorkingDirectory(pathname); ftpClient.storeFile(fileName, inputStream); inputStream.close(); ftpClient.logout(); flag = true; System.out.println("上传文件成功"); }catch (Exception e) { System.out.println("上传文件失败"); e.printStackTrace(); }finally{ if(ftpClient.isConnected()){ try{ ftpClient.disconnect(); }catch(IOException e){ e.printStackTrace(); } } if(null != inputStream){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return true; } //改变目录路径 public boolean changeWorkingDirectory(String directory) { boolean flag = true; try { flag = ftpClient.changeWorkingDirectory(directory); if (flag) { System.out.println("进入文件夹" + directory + " 成功!"); } else { System.out.println("进入文件夹" + directory + " 失败!开始创建文件夹"); } } catch (IOException ioe) { ioe.printStackTrace(); } return flag; } //创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建 public boolean CreateDirecroty(String remote) throws IOException { boolean success = true; String directory = remote + "/"; // 如果远程目录不存在,则递归创建远程服务器目录 if (!directory.equalsIgnoreCase("/") && !changeWorkingDirectory(new String(directory))) { int start = 0; int end = 0; if (directory.startsWith("/")) { start = 1; } else { start = 0; } end = directory.indexOf("/", start); String path = ""; String paths = ""; while (true) { String subDirectory = new String(remote.substring(start, end).getBytes("GBK"), "iso-8859-1"); path = path + "/" + subDirectory; if (!existFile(path)) { if (makeDirectory(subDirectory)) { changeWorkingDirectory(subDirectory); } else { System.out.println("创建目录[" + subDirectory + "]失败"); changeWorkingDirectory(subDirectory); } } else { changeWorkingDirectory(subDirectory); } paths = paths + "/" + subDirectory; start = end + 1; end = directory.indexOf("/", start); // 检查所有目录是否创建完毕 if (end <= start) { break; } } } return success; } //判断ftp服务器文件是否存在 public boolean existFile(String path) throws IOException { boolean flag = false; FTPFile[] ftpFileArr = ftpClient.listFiles(path); if (ftpFileArr.length > 0) { flag = true; } return flag; } //创建目录 public boolean makeDirectory(String dir) { boolean flag = true; try { flag = ftpClient.makeDirectory(dir); if (flag) { System.out.println("创建文件夹" + dir + " 成功!"); } else { System.out.println("创建文件夹" + dir + " 失败!"); } } catch (Exception e) { e.printStackTrace(); } return flag; } /** * 下载文件 * * @param pathname FTP服务器文件目录 * * @param filename 文件名称 * * @param localpath 下载后的文件路径 * * @return */ public boolean downloadFile(String pathname, String filename, String localpath){ boolean flag = false; OutputStream os=null; try { System.out.println("开始下载文件"); initFtpClient(); //切换FTP目录 ftpClient.changeWorkingDirectory(pathname); FTPFile[] ftpFiles = ftpClient.listFiles(); for(FTPFile file : ftpFiles){ if(filename.equalsIgnoreCase(file.getName())){ File localFile = new File(localpath + "/" + file.getName()); os = new FileOutputStream(localFile); ftpClient.retrieveFile(file.getName(), os); os.close(); } } ftpClient.logout(); flag = true; System.out.println("下载文件成功"); } catch (Exception e) { System.out.println("下载文件失败"); e.printStackTrace(); } finally{ if(ftpClient.isConnected()){ try{ ftpClient.disconnect(); }catch(IOException e){ e.printStackTrace(); } } if(null != os){ try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } return flag; } /** * 删除文件 * * @param pathname FTP服务器保存目录 * * @param filename 要删除的文件名称 * * @return */ public boolean deleteFile(String pathname, String filename){ boolean flag = false; try { System.out.println("开始删除文件"); initFtpClient(); //切换FTP目录 ftpClient.changeWorkingDirectory(pathname); ftpClient.dele(filename); ftpClient.logout(); flag = true; System.out.println("删除文件成功"); } catch (Exception e) { System.out.println("删除文件失败"); e.printStackTrace(); } finally { if(ftpClient.isConnected()){ try{ ftpClient.disconnect(); }catch(IOException e){ e.printStackTrace(); } } } return flag; } public static void main(String[] args) { FtpUtils ftp =new FtpUtils(); ftp.uploadFile("XXX", "XXX", "XXX"); //ftp.downloadFile("ftpFile/data", "123.docx", "F://"); // ftp.deleteFile("ftpFile/data", "123.docx"); System.out.println("ok"); } }
2019-4-28 update
添加了C#的版本,下面是核心的两个方法,注意,C#出了一个很诡异的问题(553) 不允许此文件名,原来是拼接linux路径的时候,不要把默认路径带进去!
private void DownFile() { string FtpFilePath = ServerPath.Text.Trim(); //远程路径 string LocalPath = downloadPath.Text.Trim()+"\\my.txt"; //下载到的本地路径 if (File.Exists(LocalPath)) { File.Delete(LocalPath); } string FTPPath = FTPAddress + FtpFilePath; //建立ftp连接 FtpWebRequest reqFtp = (FtpWebRequest)FtpWebRequest.Create(new Uri(FTPPath)); reqFtp.Method = WebRequestMethods.Ftp.DownloadFile; reqFtp.UseBinary = true; reqFtp.UsePassive = true; reqFtp.ReadWriteTimeout = 10000; reqFtp.KeepAlive = true; reqFtp.Credentials = new NetworkCredential(FTPUsername, FTPPwd); FtpWebResponse response = (FtpWebResponse)reqFtp.GetResponse(); Stream ftpStream = response.GetResponseStream(); long cl = response.ContentLength; int buffersize = 2048; int readCount; byte[] buffer = new byte[buffersize]; readCount = ftpStream.Read(buffer, 0, buffersize); //创建并写入文件 FileStream OutputStream = new FileStream(LocalPath, FileMode.Create); while (readCount > 0) { OutputStream.Write(buffer, 0, buffersize); readCount = ftpStream.Read(buffer, 0, buffersize); } ftpStream.Close(); OutputStream.Close(); response.Close(); if (File.Exists(LocalPath)) { MessageBox.Show("download OK!"); } } private void UpFile() { string LocalPath = "D:\\test.txt"; //待上传文件 FileInfo f = new FileInfo(LocalPath); string FileName = f.Name; string ftpRemotePath = "/"; string FTPPath = FTPAddress + ftpRemotePath + FileName; //上传到ftp路径,如ftp://***.***.***.**:21/home/test/test.txt //实现文件传输协议 (FTP) 客户端 FtpWebRequest reqFtp = (FtpWebRequest)FtpWebRequest.Create(new Uri(FTPPath)); reqFtp.UseBinary = true; reqFtp.Credentials = new NetworkCredential(FTPUsername, FTPPwd); //设置通信凭据 reqFtp.KeepAlive = false; //请求完成后关闭ftp连接 reqFtp.Method = WebRequestMethods.Ftp.UploadFile; reqFtp.ContentLength = f.Length; int buffLength = 2048; byte[] buff = new byte[buffLength]; int contentLen; //读本地文件数据并上传 FileStream fs = f.OpenRead(); try { Stream strm = reqFtp.GetRequestStream(); contentLen = fs.Read(buff, 0, buffLength); while (contentLen != 0) { strm.Write(buff, 0, contentLen); contentLen = fs.Read(buff, 0, buffLength); } strm.Close(); fs.Close(); MessageBox.Show("upload OK!"); } catch (Exception ex) { MessageBox.Show("upload fail!"); } }