摘要 使用Java通過JCIFS框架讀寫共享文件夾,使用SMB協議,並支持域認證。
項目常常需要有訪問共享文件夾的需求,例如讀取共享文件夾存儲的視頻、照片和PPT等文件。那么如何使用Java讀寫Windows共享文件夾呢?
使用Java訪問擁有全部讀寫權限的共享文件夾比較簡單,和普通的目錄沒有什么區別。但是,如果從Linux服務器訪問一個windows服務器上需要用戶名和密碼驗證的共享文件夾,就需要一點點小技巧了。這里介紹一個開源的庫JCIFS,他可以輕松滿足此需求。
JCIFS是使用Java語言開發的一款開源框架,通過SMB協議訪問遠程共享文件夾,就像訪問本地文件夾一樣,簡簡單單。她同時支持Windows和Linux共享文件夾,不過,Linux共享文件夾需要安裝Samba服務軟件(官網:http://www.samba.org/)。
另外,通過掛載該共享文件夾到Linux服務器下也可以實現,此時不需要借助SMB協議,對此,這里不做介紹,感興趣的童鞋可以去問問度娘。
言歸正傳,maven依賴如下:
<!-- https://mvnrepository.com/artifact/org.samba.jcifs/jcifs --> <dependency> <groupId>org.samba.jcifs</groupId> <artifactId>jcifs</artifactId> <version>1.3.3</version> </dependency>
SMB(Server Message Block)通信協議是微軟(Microsoft)和英特爾(Intel)在1987年制定的協議,主要是作為Microsoft網絡的通訊協議。SMB 是在會話層(session layer)和表示層(presentation layer)以及小部分應用層(application layer)的協議。通過設置“NetBIOS over TCP/IP”使得Samba不但能與局域網絡主機分享資源,還能與全世界的電腦分享資源。
代碼示例:
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; import jcifs.smb.NtlmPasswordAuthentication; import jcifs.smb.SmbFile; import jcifs.smb.SmbFileInputStream; import jcifs.smb.SmbFileOutputStream; public class SmbFileUtil { private static Logger log = LoggerFactory.getLogger(SmbFileUtil.class); private static String USER_DOMAIN = "yourDomain"; private static String USER_ACCOUNT = "yourAccount"; private static String USER_PWS = "yourPassword"; public static void main(String[] args) throws Exception { // remoteUrl 格式示例 【smb://132.20.2.33/CIMPublicTest/】 // 目錄 String shareDir = "smb:// 132.20.2.33/CIMPublicTest/"; listFiles(shareDir); } /** * @Title listFiles * @Description 遍歷指定目錄下的文件 * @date 2019-01-11 09:56 */ private static void listFiles(String shareDirectory) throws Exception { long startTime = System.currentTimeMillis(); // 域服務器驗證 NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(USER_DOMAIN, USER_ACCOUNT, USER_PWS); SmbFile remoteFile = new SmbFile(shareDirectory, auth); log.info("遠程共享目錄訪問耗時:【{}】", System.currentTimeMillis() - startTime); if (remoteFile.exists()) { SmbFile[] files = remoteFile.listFiles(); remoteFile.listFiles(shareDirectory); for (SmbFile f : files) { log.info(f.getName()); } } else { log.info("文件不存在"); } } }
NtlmPasswordAuthentication類用於域認證,需要三個參數, 第一個是域名,如果沒有,就賦值null, 第二個是用戶名,第三個是密碼。下面列舉SMB協議的兩個應用場景。SmbFile類和Java的File類十分相似,使用其對象可以處理遠程共享文件的讀寫。
/** * @Title smbGet * @Param shareUrl 共享目錄中的文件路徑,如smb://132.20.2.33/CIMPublicTest/eg.txt * @Param localDirectory 本地目錄,如tempStore/smb */ public static void smbGet(String shareUrl, String localDirectory) throws Exception { NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(USER_DOMAIN, USER_ACCOUNT, USER_PWS); SmbFile remoteFile = new SmbFile(shareUrl, auth); if (!remoteFile.exists()) { log.info("共享文件不存在"); return; } // 有文件的時候再初始化輸入輸出流 InputStream in = null; OutputStream out = null; log.info("下載共享目錄的文件 shareUrl 到 localDirectory"); try { String fileName = remoteFile.getName(); File localFile = new File(localDirectory + File.separator + fileName); File fileParent = localFile.getParentFile(); if (null != fileParent && !fileParent.exists()) { fileParent.mkdirs(); } in = new BufferedInputStream(new SmbFileInputStream(remoteFile)); out = new BufferedOutputStream(new FileOutputStream(localFile)); byte[] buffer = new byte[1024]; while (in.read(buffer) != -1) { out.write(buffer); buffer = new byte[1024]; } out.flush(); //刷新緩沖區輸出流 } catch (Exception e) { e.printStackTrace(); } finally { out.close(); in.close(); } } /** * * @Title smbPut * @Description 向共享目錄上傳文件 * @Param shareDirectory 共享目錄 * @Param localFilePath 本地目錄中的文件路徑 * @date 2019-01-10 20:16 */ public static void smbPut(String shareDirectory, String localFilePath) { InputStream in = null; OutputStream out = null; try { File localFile = new File(localFilePath); String fileName = localFile.getName(); SmbFile remoteFile = new SmbFile(shareDirectory + "/" + fileName); in = new BufferedInputStream(new FileInputStream(localFile)); out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile)); byte[] buffer = new byte[1024]; while (in.read(buffer) != -1) { out.write(buffer); buffer = new byte[1024]; } out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); in.close(); } catch (IOException e) { e.printStackTrace(); } } }