使用SMBJ协议远程传输文件到共享文件夹
SMBJ概述
SMB(Server Message Block)通信协议是微软(Microsoft)和英特尔(Intel)在1987年制定的协议,主要是作为Microsoft网络的通讯协议。SMB 是在会话层(session layer)和表示层(presentation layer)以及小部分应用层(application layer)的协议。
SMBJ的版本问题
随着windows版本的升级,SMBJ的版本也从最初的SMBJ1.0到现在的SMBJ3.0,其安全性也是不断的提高。SMBJ1.0存在较大的安全问题,具体你可以自己了解一下,以下是各个windows版本跟smbj协议的对照表
使用SMBJ协议上传文件到远程文件夹
如果你的远程文件夹的windows系统版本较为古老,Windows2003或者其他的,你需要使用jcifs jar包上传文件,在对应的pom文件加入以下依赖
<dependency>
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.2.25</version>
</dependency>
如果windows系统支持SMBJ2.0或以上的版本,你可以使用smbj jar包上传
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>smbj</artifactId>
<version>0.10.0</version>
</dependency>
同时使用这两个jar包,就可以支持到不同的版本的SMBJ协议。
代码示例
以下是我jcifs+smbj上传文件的示例,第一个try是尝试使用smbj协议上传文件,如果失败的话,在catch中使用jcifs尝试上传。具体可以看代码,当然得保证连接服务器的信息正确。
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msfscc.FileAttributes;
import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation;
import com.hierynomus.mssmb2.SMB2CreateDisposition;
import com.hierynomus.mssmb2.SMB2CreateOptions;
import com.hierynomus.mssmb2.SMB2ShareAccess;
import com.hierynomus.smbj.SMBClient;
import com.hierynomus.smbj.SmbConfig;
import com.hierynomus.smbj.auth.AuthenticationContext;
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.smbj.share.File;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileOutputStream;
import java.io.*;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/*
* https://www.javadoc.io/static/com.hierynomus/smbj/0.10.0/com/hierynomus/smbj/SMBClient.html
* */
public class SmbjTest {
static void uploadFile2(String hostname, String username, String password, String domain, String folderName){
String localFile = "D:\\1.xlsx"; // 本地要上传的文件
SmbConfig config = SmbConfig.builder()
.withTimeout(120, TimeUnit.SECONDS) // Timeout sets Read, Write, and Transact timeouts (default is 60 seconds)
.withSoTimeout(180, TimeUnit.SECONDS) // Socket Timeout (default is 0 seconds, blocks forever)
.build();
SMBClient client = new SMBClient(config);
try (Connection connection = client.connect(hostname)) {
AuthenticationContext ac = new AuthenticationContext(username, password.toCharArray(), domain);
Session session = connection.authenticate(ac);
try (DiskShare share = (DiskShare) session.connectShare(folderName)) {
System.out.println("connect smbj success");
Set<AccessMask> accessMasks = new HashSet<>();
accessMasks.add(AccessMask.FILE_ADD_FILE);
Set<FileAttributes> attributes = new HashSet<>();
attributes.add(FileAttributes.FILE_ATTRIBUTE_NORMAL);
Set<SMB2ShareAccess> smb2ShareAccesses= new HashSet<>();
smb2ShareAccesses.add(SMB2ShareAccess.FILE_SHARE_WRITE);
Set<SMB2CreateOptions> smb2CreateOptions= new HashSet<>();
smb2CreateOptions.add(SMB2CreateOptions.FILE_RANDOM_ACCESS);
// System.out.println(1234);
File openFile = share.openFile("5.xlsx", accessMasks, attributes, smb2ShareAccesses, SMB2CreateDisposition.FILE_OVERWRITE_IF, smb2CreateOptions);
OutputStream oStream = openFile.getOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(localFile));
byte[] buffer = new byte[1024];
int len = 0; //Read length
while ((len = in.read(buffer, 0, buffer.length)) != -1) {
oStream.write(buffer, 0, len);
}
oStream.flush();
oStream.close();
System.out.println("open file");
}catch (Exception e){
System.out.println("err1");
e.printStackTrace();
}
} catch (Exception e) {
System.out.println("connect smbj fail");
System.out.println(e.getMessage());
System.out.println("try to connect jcifs.... ");
String url = "smb://"+username+":"+password+"@"+hostname+"/"+folderName;
try{
SmbFile smbFile = new SmbFile(url);
smbFile.connect();
System.out.println("jcifs connect successful");
java.io.File file = new java.io.File(localFile);
try {
int flag =-1;
System.out.println(url + "/"
+ file.getName());
SmbFileOutputStream smbOut = new SmbFileOutputStream(url + "/"
+ file.getName(), false);
BufferedInputStream bf = new BufferedInputStream(new FileInputStream(file));
byte[] bt = new byte[1024];
int n = bf.read(bt);
while (n != -1) {
smbOut.write(bt, 0, n);
smbOut.flush();
n = bf.read(bt);
}
flag = 0;
System.out.println("文件传输结束...");
} catch (SmbException smbException) {
e.printStackTrace();
System.out.println(smbException);
}
}catch (Exception smbException){
smbException.printStackTrace();
}
}
}
/**
* 把一个文件转化为byte字节数组。
*
* @return
*/
private static byte[] fileConvertToByteArray(java.io.File file) {
byte[] data = null;
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
byte[] buffer = new byte[1024];
while ((len = fis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
data = baos.toByteArray();
fis.close();
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
public static void main(String[] args) {
SmbjTest.uploadFile2("hostname", "username", "password", "domain", "folderName");
}
}
相关文档
SMBJ协议的错误码解析:https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/8f11e0f3-d545-46cc-97e6-f00569e3e1bc?redirectedfrom=MSDN
SMBJ协议版本信息:http://woshub.com/smb-1-0-support-in-windows-server-2012-r2/#!prettyPhoto