Linux下vsftpd的安裝,Java上傳文件實現。


 首先我們需要查看是否已經安裝vsftpd,輸入命令 :vsftpd  -v。如果出現以下信息,那么就說明已經安裝vsftpd

如果沒有安裝,那么輸入命令   : yum  install vsftpd -y 進行安裝,出現complete說明安裝成功。

現在去我們先創建一下用戶 , 命令:useradd  -d /home/ftpuser ftpuser   -d是為用戶ftpuser 指定主目錄,默認是/home下對應用戶名的一個文件夾。

接着設置用戶密碼 : passwd ftpuser .輸入兩次以后顯示successfully就說明設置好了。

接着我們需要查看一下本機外網訪問權限,這個一定要開。不然會執行失敗:輸入 getsebool -a |grep ftp 

我們發現這兩個狀態是關着的,我們要把他開起來,同事也要關閉防火牆

這樣子就開起來了。接下去我們需要配置一下vsftpd 的配置文件 進入配置文件目錄

其實默認的配置文件就可以滿足基本的功能,如果我們需要關閉匿名操作,那么我們把anonymous_enable設置為NO就可以了。

vsftpd的默認端口為21,在不太了解vsftpd的情況下,切記不要去改他。一定不要去改,一定不要!!

接下去就是JAVA代碼了

上傳功能的代碼:上傳過程可能遇到進入文件夾失敗,這里推薦大家用絕對路徑!!!

/**
	 * 初始化ftp服務器
	 * 
	 * @throws IOException
	 * @throws SocketException
	 */
	public void initFtpClient() throws SocketException, IOException {
		ftpClient = new FTPClient();
		ftpClient.setControlEncoding("utf-8");
		LOGGER.info("connecting...ftp服務器:" + this.hostname + ":" + this.port);
		ftpClient.connect(hostname, port); // 連接ftp服務器
		ftpClient.login(username, password); // 登錄ftp服務器
		int replyCode = ftpClient.getReplyCode(); // 是否成功登錄服務器
		if (!FTPReply.isPositiveCompletion(replyCode)) {
			LOGGER.info("connect failed...ftp服務器:" + this.hostname + ":" + this.port);
		}
		LOGGER.info("connect successfu...ftp服務器:" + this.hostname + ":" + this.port);

	}

	/**
	 * 上傳文件
	 * 
	 * @param pathname
	 *            ftp服務保存地址
	 * @param fileName
	 *            上傳到ftp的文件名
	 * @param inputStream
	 *            輸入文件流
	 * @return
	 * @throws IOException
	 */
	public boolean uploadFile(String pathname, String fileName, InputStream inputStream) throws IOException {
		boolean flag = false;
		initFtpClient();
		try {
			LOGGER.info("開始上傳文件");
			ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
//			CreateDirecroty(pathname);
			
			boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(pathname);
			if(changeWorkingDirectory) {
				LOGGER.info("進入文件"+pathname+"夾成功.");
			}else {
				LOGGER.info("進入文件"+pathname+"夾失敗.開始創建文件夾");
				boolean makeDirectory = ftpClient.makeDirectory(pathname);
				if(makeDirectory) {
					LOGGER.info("創建文件夾"+pathname+"成功");
					boolean changeWorkingDirectory2 = ftpClient.changeWorkingDirectory(pathname);
					if(changeWorkingDirectory2) {
						LOGGER.info("進入文件"+pathname+"夾成功.");
					}
				}else {
					LOGGER.info("創建文件夾"+pathname+"失敗");
				}
			}
			ftpClient.storeFile(fileName, inputStream);
			inputStream.close();
			ftpClient.logout();
			flag = true;
			if (flag) {

				LOGGER.info("上傳文件成功");
			}
		} 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;
	} 

接下去就是上傳的功能了,我這里約到一個很奇怪的現象,就是通過ftpclientd獲取文件列表的時候有隨機性,有時候可以獲取到,有時候卻是空的,就是ftpclient.listFiles()方法。網上的說法是添加方法ftpClient.enterLocalPassiveMode();,可是我這里添加了這個方法就連接超時。也有人說是防火牆一系列問題。那么首先是vsftpd的主動被動問題。vsftpd的配置文件是默認啟用的主動模式。要改成被動模式的話,這邊需要修改配置文件,我用的主動模式 。輸入命令 vim /etc/vsftpd/vsftpd.conf  ,修改之前記得先備份一份配置文件。 然后:

這么改,啟動被動模式,關閉主動模式,隨后重啟vsftpd.我試過僅僅這樣子改是不行的,我們需要去查看一下SELinux防火牆的狀態:

我這里是寬容模式。SELinux有3種狀態,Permissive (寬容模式), Disabled , Enforcing(強制)在配置文件/etc/selinux/config中定義,要永久關閉SELinux防火牆需要將SELINUX=Permissive改為SELINUX=disabled,這里一定要重啟系統。如果是啟用就將disabled改成其他的,也需要重啟。我這邊是強制改成寬容,只需要輸入命令setenforce 1 就可以了,不需要重啟計算機。修改完這里,我們還要設置防火牆FireWall防火牆。

firewall-cmd --permanent --zone=public --add-port=10090-10100/tcp

firewall-cmd --reload

顯示success就可以了。。。

接下去要增加兩個模塊。。不然被動模式會連接失敗,編輯  /etc/sysconfig/iptables-config  文件

IPTABLES_MODULES="ip_conntrack_ftp"
IPTABLES_MODULES="ip_nat_ftp"

添加完這兩行 保存設置  firewall-cmd --reload 。 

這里的配置有亂,我后來把防火牆也禁用了。SELinux也禁用了。

可能根本不需要這些配置,大家在實操的時候可以先把防火牆跟SELinux都先禁用。看看實際運行情況再考慮要不要做這些配置,我這里是遇到獲取不到文件。所以百度了很多文章,做了很多配置,畢竟不熟悉。

接下去就是下載 跟 刪除的代碼了:

/**
	 * * 下載文件 *
	 * 
	 * @param pathname
	 *            FTP服務器文件目錄 *
	 * @param filename
	 *            文件名稱 *
	 * @param localpath
	 *            下載后的文件路徑 *
	 * @return
	 * @throws IOException 
	 */
	public byte[] downloadFile(String pathname, String filename, String localpath) throws IOException {
		boolean flag = false;
		OutputStream os = null;
		byte[] buffer = null;
		initFtpClient();
		try {
			LOGGER.info("開始下載文件");
//			ftpClient.enterLocalPassiveMode();
//			FTPClientConfig conf = new FTPClientConfig( FTPClientConfig.SYST_UNIX);
//			ftpClient.configure(conf);
			// 切換FTP目錄
			boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(pathname);
			if(!changeWorkingDirectory) {
				throw new FTPTransferException(FTPError.changeDirectoryError) ;
			}else {
				LOGGER.info("進入目"+pathname+"錄成功。");
			}

			FTPFile[] ftpFiles = ftpClient.listFiles(pathname, new FTPFileFilter() {

				@Override
				public boolean accept(FTPFile file) {
					if (file.getName().equals(filename)) {
						return true;
					}
					return false;
				}
			});
			for (int i=0;i<ftpFiles.length && flag ==false;i++) {
				FTPFile file = ftpFiles[i];
				if (filename.equalsIgnoreCase(file.getName())) {
					flag = true;
					setFileSize(file.getSize());
					InputStream fis = ftpClient.retrieveFileStream(file.getName());
					buffer = new byte[fis.available()];
					int read = fis.read(buffer);
					fis.close();
					LOGGER.info("下載文件成功");
				}
			}
			ftpClient.logout();

		}  finally {
			if (ftpClient.isConnected()) {
				try {
					ftpClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != os) {
				try {
					os.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return buffer;
	}

	/**
	 * * 刪除文件 *
	 * 
	 * @param pathname
	 *            FTP服務器保存目錄 *
	 * @param filename
	 *            要刪除的文件名稱 *
	 * @return
	 * @throws IOException 
	 */
	public boolean deleteFile(String pathname, String filename) throws IOException {
		boolean flag = false;
		try {
			LOGGER.info("開始刪除文件");
			initFtpClient();
			// 切換FTP目錄
			boolean changeWorkingDirectory = ftpClient.changeWorkingDirectory(pathname);
			if(!changeWorkingDirectory) {
				throw new FTPTransferException(FTPError.changeDirectoryError) ;
			}else {
				LOGGER.info("進入目"+pathname+"錄成功。");
			}

			FTPFile[] ftpFiles = ftpClient.listFiles(pathname, new FTPFileFilter() {

				@Override
				public boolean accept(FTPFile file) {
					if (file.getName().equals(filename)) {
						return true;
					}
					return false;
				}
			});
			if (ftpFiles == null || ftpFiles.length == 0) {
				LOGGER.info("刪除文件失敗,文件不存在");
				throw new FTPTransferException(FTPError.fileNotFound) ;
			} else {

				ftpClient.dele(filename);
				ftpClient.logout();
				flag = true;
			}
			if(flag) {
				
				LOGGER.info("刪除文件成功");
			}
		} finally {
			if (ftpClient.isConnected()) {
				try {
					ftpClient.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return flag;
	}

這樣下來基本功能就差不多都可以實現了。。經過驗證,獲取不到列表的我,應該不是主動被動的關系,到最后我還是改成了主動,最終確定是SELinux的鍋,一定把他的強制模式關閉。在調試前,一定要看看SELinux的狀態,跟防火牆的狀態。都給他關了 排除干擾,一般來說程序就沒什么問題了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM