在Java程序中读写windows共享文件夹
摘要 使用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(); } } }