前言 最近有項目需要開發檔案打包下載功能,其中包含很多大附件,項目使用minio存儲且不在同一臺伺服器上,為了優化速度決定使用windows共用功能進行文件傳輸 SMB1.0 集成jcifs類庫,主要適用於一些老舊系統,但下載速度比較慢,僅作參考 此類庫沒有maven引用,官網地址:http://j ...
前言
最近有項目需要開發檔案打包下載功能,其中包含很多大附件,項目使用minio存儲且不在同一臺伺服器上,為了優化速度決定使用windows共用功能進行文件傳輸
SMB1.0
集成jcifs類庫,主要適用於一些老舊系統,但下載速度比較慢,僅作參考
此類庫沒有maven引用,官網地址:http://jcifs.samba.org/
註意事項:
設置jcifs.smb.client.dfs.disabled選項開啟,可以提高傳輸速度
使用NtlmPasswordAuthentication認證代替smb協議url攜帶用戶名密碼方式,避免特殊字元傳遞造成認證失敗
public static void downloadFile(String ip, String shareFolder, String filePath, String localDir) throws Exception {
System.setProperty("jcifs.smb.client.dfs.disabled", "true");
String url = getFileUrl(ip, shareFolder, filePath);
SmbFile smbFile = new SmbFile(url);
smbFile.connect();
FileUtil.initfloderPath(localDir);
String localFilePath = localDir + "/" + smbFile.getName();
BufferedInputStream buf = new BufferedInputStream(new SmbFileInputStream(smbFile));
FileUtil.writeFile(localFilePath, FileUtil.convertStreamToByte(buf));
}
public static void downloadFileByAuth(String ip, String shareFolder, String userName, String password, String filePath, String localDir) throws Exception {
System.setProperty("jcifs.smb.client.dfs.disabled", "true");
String url = getFileUrl(ip, shareFolder, filePath);
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(ip, userName, password);
SmbFile smbFile = new SmbFile(url, auth);
smbFile.connect();
FileUtil.initfloderPath(localDir);
String localFilePath = localDir + "/" + smbFile.getName();
BufferedInputStream buf = new BufferedInputStream(new SmbFileInputStream(smbFile));
FileUtil.writeFile(localFilePath, FileUtil.convertStreamToByte(buf));
}
public static String getFileUrl(String ip, String shareFolder, String filePath) {
return "smb://" + ip + "/" + shareFolder + "/" + filePath;
}
SMB2.0
集成smbj類庫,適用於windows server2012及以上操作系統,預設安裝開啟無需額外配置
此類庫maven引用很久沒有發佈最新版本,需要下載代碼自行編譯,github地址:https://github.com/hierynomus/smbj
經測試,500MB文件傳輸大概比minio協議傳輸快了4秒左右,小文件傳輸速度基本保持一致
public static void downloadFileV2(String ip, String shareFolder, String filePath, String localDir) throws Exception {
SMBClient client = new SMBClient(SmbConfig.createDefaultConfig());
Connection conn = client.connect(ip);
Session session = conn.authenticate(AuthenticationContext.anonymous());
downLoadSMB2(session, shareFolder, filePath, localDir);
}
public static void downloadFileByAuthV2(String ip, String shareFolder, String userName, String password, String filePath, String localDir) throws Exception {
SMBClient client = new SMBClient(SmbConfig.createDefaultConfig());
Connection conn = client.connect(ip);
Session session = conn.authenticate(new AuthenticationContext(userName, password.toCharArray(), ip));
downLoadSMB2(session, shareFolder, filePath, localDir);
}
private static void downLoadSMB2(Session session, String shareFolder, String filePath, String localDir) throws Exception {
InputStream fis = null;
FileOutputStream os = null;
DiskShare diskShare = null;
try {
diskShare = (DiskShare) session.connectShare(shareFolder);
if (!diskShare.fileExists(filePath)) {
throw new FileNotFoundException(filePath);
}
if (!diskShare.isConnected())
diskShare = (DiskShare) session.connectShare(shareFolder);
com.hierynomus.smbj.share.File file = diskShare.openFile(filePath,
EnumSet.of(AccessMask.GENERIC_READ),
(Set) null,
SMB2ShareAccess.ALL,
SMB2CreateDisposition.FILE_OPEN,
(Set) null
);
fis = file.getInputStream();
FileUtil.initfloderPath(localDir);
String[] filePathList = filePath.split("\\/");
String localFilePath = localDir + "/" + filePathList[filePathList.length - 1];
os = new FileOutputStream(localFilePath);
byte[] b = new byte[4096];
int length;
while ((length = fis.read(b)) > 0) {
os.write(b, 0, length);
}
} catch (IOException e) {
throw e;
} finally {
IOUtils.close(os);
IOUtils.close(fis);
if (diskShare != null && diskShare.isConnected()) diskShare.close();
}
}
445埠被禁用解決辦法
一般企業/政府項目為了系統安全會禁用445埠,而445埠禁用後文件共用功能無法使用,此時我們需要進行埠轉發,即將客戶端445埠轉發到共用伺服器埠A,共用伺服器將本地埠A轉發到445即可完成共用,具體操作步驟如下,192.168.1.164就是共用文件伺服器的內網ip
查看伺服器轉發規則
netsh interface portproxy show all
刪除伺服器轉發規則
netsh interface portproxy reset
共用文件伺服器
- 執行CMD代碼
netsh interface portproxy add v4tov4 listenport=4455 listenaddress=192.168.1.164 connectport=445 connectaddress=127.0.0.1
netsh interface portproxy add v4tov4 listenport=4455 listenaddress=127.0.0.1 connectport=445 connectaddress=127.0.0.1
客戶端伺服器
- 關閉Server服務
- CMD執行代碼
netsh interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=445 connectaddress=192.168.1.164 connectport=4455
- 重啟系統