· SMB 1.0
SMB1.0协议由于在文件共享传输过程中存在的传输效率低以及传输空间小等缺陷逐渐被抛弃了。为了更好的实现网络中文件的共享,在SMB1.0基础上开发了新的网络文件传输协议,即SMB2.0。
· SMB 2.0
· 相比SMB1.0,提供了文件共享传输过程中的传输效率、文件缓存空间以及文件并发传输等问题。
· SMB2.0加入了对文件传输过程中的安全性保障机制,使得文件共享传输过程中可以避免信息截取等恶意攻击。
· SMB 3.0
· SMB3.0在Windows Server 2012操作系统中出现,与Windows 8客户端共同工作。
· SMB3.0极大的提升了性能、可靠性和安全性。
· 当它与Windows Storage Spaces(Windows Server 2012的一个功能,将普通的磁盘虚拟化为高性能、高可用性的存储)结合时,SMB3.0可以使用廉价的直连存储(DAS)、JBOD或RBOD,创建一个特定的NAS设备。
· Maven 依赖
SMB2.0和SMB3.0协议与SMB1.0协议依赖的JAR不一样,SMB1.0依赖jcifs:jcifs:1.3.17,SMB2.0和SMB3.0依赖com.hierynomus:smbj。
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>smbj</artifactId>
<version>0.10.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
· SMB 2.0和3.0协议工具类
package com.arhorchin.securitit.protocol.smb;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.EnumSet;
import org.apache.log4j.Logger;
import com.hierynomus.msdtyp.AccessMask;
import com.hierynomus.msfscc.FileAttributes;
import com.hierynomus.mssmb2.SMB2CreateDisposition;
import com.hierynomus.mssmb2.SMB2CreateOptions;
import com.hierynomus.mssmb2.SMB2ShareAccess;
import com.hierynomus.smbj.SMBClient;
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;
public class SmbV23Util {
/**
* logger.
*/
private static Logger logger = Logger.getLogger(SmbV23Util.class);
/**
* SMB下载文件.
* @param remoteIp 远程IP.
* @param remoteUrl 远程地址.
* @param username 远程用户.
* @param password 远程密码.
* @param filename 远程文件.
* @return 共享文件.
*/
public static byte[] smbDownload(String remoteIp, String remoteUrl, String username, String password,
String filename) {
File shareFile = null;
InputStream shareIs = null;
ByteArrayOutputStream shareBaos = null;
SMBClient client = null;
Session session = null;
DiskShare diskShare = null;
Connection connection = null;
AuthenticationContext authenticationContext = null;
try {
client = new SMBClient();
connection = client.connect(remoteIp);
// 创建连接会话.
authenticationContext = new AuthenticationContext(username, password.toCharArray(), null);
session = connection.authenticate(authenticationContext);
// 操作共享文件.
diskShare = (DiskShare) session.connectShare(remoteUrl);
// 获取文件流.上传文件.
shareFile = diskShare.openFile(filename, EnumSet.of(AccessMask.GENERIC_READ),
EnumSet.of(FileAttributes.FILE_ATTRIBUTE_NORMAL), SMB2ShareAccess.ALL,
SMB2CreateDisposition.FILE_OPEN_IF, EnumSet.noneOf(SMB2CreateOptions.class));
shareIs = shareFile.getInputStream();
// 读取文件并下载.
shareBaos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (shareIs.read(buffer) != -1) {
shareBaos.write(buffer);
buffer = new byte[1024];
}
return shareBaos.toByteArray();
} catch (Exception ex) {
logger.error(ex);
return null;
} finally {
try {
if (null != shareIs) {
shareIs.close();
}
if (null != diskShare) {
diskShare.close();
}
if (null != session) {
session.close();
}
if (null != client) {
client.close();
}
} catch (IOException ex) {
logger.error(ex);
return null;
}
}
}
/**
* SMB上传文件.
* @param remoteIp 远程IP.
* @param remoteUrl 远程地址.
* @param username 远程用户.
* @param password 远程密码.
* @param filename 远程文件.
* @param fileBytes 待上传文件.
* @return 上传结果.
*/
public static boolean smbUpload(String remoteIp, String remoteUrl, String username, String password,
String filename, byte[] fileBytes) {
File shareFile = null;
String[] filepathArr = null;
String vfilepath = null;
OutputStream shareOs = null;
SMBClient client = null;
Session session = null;
DiskShare diskShare = null;
Connection connection = null;
AuthenticationContext authenticationContext = null;
try {
client = new SMBClient();
connection = client.connect(remoteIp);
// 创建连接会话.
authenticationContext = new AuthenticationContext(username, password.toCharArray(), null);
session = connection.authenticate(authenticationContext);
// 操作共享文件.
diskShare = (DiskShare) session.connectShare(remoteUrl);
if (filename.contains("/") || filename.contains("\\")) {
filename = filename.replaceAll("\\\\", "/");
filepathArr = filename.split("/");
vfilepath = "";
for (int index = 0; index < filepathArr.length - 1; index++) {
vfilepath += filepathArr[index] + "/";
if (!diskShare.folderExists(vfilepath)) {
diskShare.mkdir(vfilepath);
}
}
}
// 获取文件流.上传文件.
shareFile = diskShare.openFile(filename, EnumSet.of(AccessMask.GENERIC_WRITE),
EnumSet.of(FileAttributes.FILE_ATTRIBUTE_NORMAL), SMB2ShareAccess.ALL,
SMB2CreateDisposition.FILE_OPEN_IF, EnumSet.noneOf(SMB2CreateOptions.class));
shareOs = shareFile.getOutputStream();
shareOs.write(fileBytes);
return true;
} catch (Exception ex) {
logger.error(ex);
return false;
} finally {
try {
if (null != shareOs) {
shareOs.close();
}
if (null != diskShare) {
diskShare.close();
}
if (null != session) {
session.close();
}
if (null != client) {
client.close();
}
} catch (IOException ex) {
logger.error(ex);
return false;
}
}
}
/**
* SMB删除文件.
* @param remoteIp 远程IP.
* @param remoteUrl 远程地址.
* @param username 远程用户.
* @param password 远程密码.
* @param filename 远程文件.
* @return 删除结果.
*/
public static boolean smbDelete(String remoteIp, String remoteUrl, String username, String password,
String filename) {
SMBClient client = null;
Session session = null;
DiskShare diskShare = null;
Connection connection = null;
AuthenticationContext authenticationContext = null;
try {
client = new SMBClient();
connection = client.connect(remoteIp);
// 创建连接会话.
authenticationContext = new AuthenticationContext(username, password.toCharArray(), null);
session = connection.authenticate(authenticationContext);
// 操作共享文件.
diskShare = (DiskShare) session.connectShare(remoteUrl);
// 获取文件流.上传文件.
diskShare.rm(filename);
return true;
} catch (Exception ex) {
logger.error(ex);
return false;
} finally {
try {
if (null != diskShare) {
diskShare.close();
}
if (null != session) {
session.close();
}
if (null != client) {
client.close();
}
} catch (IOException ex) {
logger.error(ex);
return false;
}
}
}
}
测试类如下:
package com.arhorchin.securitit.protocol.smb;
import java.io.File;
import org.apache.commons.io.FileUtils;
import com.arhorchin.securitit.protocol.smb.SmbV23Util;
public class SmbV23UtilTester {
public static void main(String[] args) throws Exception {
String remoteIp = "127.0.0.1";
String remoteUrl = "Storage";
String username = "Securitit";
String password = "Wang@881216";
String filename = "demo.png";
byte[] fileBytes = FileUtils.readFileToByteArray(new File("C:/Users/Administrator/Downloads/个人文件/demo.png"));
// 上传文件.
SmbV23Util.smbUpload(remoteIp, remoteUrl, username, password, filename, fileBytes);
// 下载文件.
byte[] downBytes = SmbV23Util.smbDownload(remoteIp, remoteUrl, username, password, filename);
System.out.println(downBytes.length);
// 删除文件.
SmbV23Util.smbDelete(remoteIp, remoteUrl, username, password, filename);
}
}
上面测试类执行的同时,观察共享文件夹,可以看到:
1) 共享文件夹首先上传了一个文件demo.pdf。
2) 测试类从共享文件夹下载了刚才上传的文件,并输出了文件长度。
3) 共享文件夹内的文件被删除掉了。
· 总结
· Windows 8及以上版本操作系统,直接提供了SMN2.0和SMB3.0,无需重新开启。
· SmbV23Util工具类可以直接复制使用,已经经过简单测试,只需按照文中要求导入Maven依赖即可。
· SmbV23Util中写法已经避免了用户名和密码中包含特殊字符的问题,如果使用完整地址方式访问,无法有效处理用户名和密码中的特殊字符。