摘要 使用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();
}
}
}
