SMB 共享目录递归遍历文档
一、背景说明
我们需要通过 Java 程序访问 SMB 协议的共享目录,递归遍历目标路径下的所有文件和子目录,输出其基本信息(名称、类型、大小等)。本文档提供完整的代码实现和操作说明。
二、开发环境
- 语言:Java
- 依赖库:
- SMBJ:用于实现 SMB 协议的交互。
Maven 依赖
在项目的 pom.xml
文件中添加 SMBJ 的依赖:
xml
复制代码
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>smbj</artifactId>
<version>0.13.0</version>
</dependency>
三、代码实现
完整代码
java
复制代码
import com.hierynomus.smbj.SMBClient;
import com.hierynomus.smbj.connection.Connection;
import com.hierynomus.smbj.session.Session;
import com.hierynomus.smbj.share.DiskShare;
import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation;
public class SMBRecursiveDirectoryExample {
public static void main(String[] args) {
// 目标 SMB 服务器和共享目录信息
String serverAddress = "x.x.x.x"; // SMB 服务器地址
String domain = "x"; // 域/工作组
String username = "x"; // 用户名
String password = "xxx"; // 密码
String shareName = "管理中心"; // SMB 共享文件夹名称
String startPath = "07人事管理\\02员工档案"; // 起始路径
// 创建 SMB 客户端实例
SMBClient client = new SMBClient();
try (Connection connection = client.connect(serverAddress)) {
// 使用指定的域、用户名和密码认证
Session session = connection.authenticate(
new com.hierynomus.smbj.auth.AuthenticationContext(username, password.toCharArray(), domain)
);
// 连接到共享目录
DiskShare share = (DiskShare) session.connectShare(shareName);
// 打印共享目录内容(递归遍历)
System.out.println("共享目录内容:");
listDirectory(share, startPath, 0); // 从指定路径开始遍历
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 递归遍历目录内容
*
* @param share SMB 共享实例
* @param path 当前目录路径
* @param level 当前目录层级,用于缩进
*/
private static void listDirectory(DiskShare share, String path, int level) {
try {
// 获取指定路径下的文件和目录列表
for (FileIdBothDirectoryInformation item : share.list(path)) {
String name = item.getFileName();
// 跳过当前目录和父目录
if (name.equals(".") || name.equals("..")) continue;
// 判断是否是目录
boolean isDirectory = (item.getFileAttributes() & 0x10) != 0;
// 打印目录或文件名,并根据层级增加缩进
System.out.printf("%s名称: %s, 是否目录: %b, 大小: %d 字节\n",
" ".repeat(level), name, isDirectory, item.getEndOfFile());
// 如果是目录,递归遍历子目录
if (isDirectory) {
String subPath = path.isEmpty() ? name : path + "\\" + name;
listDirectory(share, subPath, level + 1);
}
}
} catch (Exception e) {
System.err.printf("无法访问目录 %s: %s\n", path, e.getMessage());
}
}
}
四、代码逻辑详解
1. 主方法
- 定义 SMB 服务器地址、用户凭据和共享目录信息。
- 创建
SMBClient
实例,建立连接并认证。 - 使用
DiskShare
接口访问共享目录。 - 从指定路径开始递归遍历目录内容。
2. 递归方法 listDirectory
功能
- 遍历给定路径下的所有文件和目录。
- 输出文件/目录的名称、类型和大小。
- 对于目录,递归调用自身以深入子目录。
关键实现
- 过滤系统目录:通过跳过
"."
和".."
避免循环引用。 - 目录判断:通过文件属性中的
0x10
位判断是否为目录:
java
复制代码
boolean isDirectory = (item.getFileAttributes() & 0x10) != 0;
- 路径拼接:根据当前路径动态生成子目录路径:
java
复制代码
String subPath = path.isEmpty() ? name : path + "\\" + name;
五、运行结果
假设共享目录 \\x.x.x.x\管理中心\07人事管理\02员工档案
的结构如下:
markdown
复制代码
02员工档案
├── 文件1.txt
├── 文件2.pdf
└── 子文件夹
├── 子文件1.docx
└── 子文件2.xlsx
程序运行后输出如下:
yaml
复制代码
共享目录内容:
名称: 文件1.txt, 是否目录: false, 大小: 1234 字节
名称: 文件2.pdf, 是否目录: false, 大小: 5678 字节
名称: 子文件夹, 是否目录: true, 大小: 0 字节
名称: 子文件1.docx, 是否目录: false, 大小: 3456 字节
名称: 子文件2.xlsx, 是否目录: false, 大小: 7890 字节
六、常见问题及解决方案
1. 访问无权限目录
问题:某些目录无法访问,抛出异常。 解决:
- 确保 SMB 用户有足够权限访问目标目录及其子目录。
- 捕获异常并输出错误信息,跳过无权限目录。
2. 中文路径编码问题
问题:路径包含中文时,可能抛出 FileNotFoundException
。 解决:
- 确保项目使用 UTF-8 编码。
- 检查 SMB 服务器是否支持 Unicode。
3. 文件属性获取异常
问题:无法判断文件是否为目录。 解决:
- 使用
getFileAttributes()
返回值的位运算判断属性。
七、总结
本文档通过 Java 和 SMBJ 库实现了 SMB 共享目录的递归遍历,解决了中文路径处理、目录权限不足等问题。代码逻辑清晰,可扩展性强,适用于大多数 SMB 文件共享场景。