
本文介绍如何使用 java 标准 nio.2 api 遍历目录并检测 ntfs 文件系统上的替代数据流(alternate data streams),通过 userdefinedfileattributeview 获取流名称与大小,无需外部命令或 jni。
本文介绍如何使用 java 标准 nio.2 api 遍历目录并检测 ntfs 文件系统上的替代数据流(alternate data streams),通过 userdefinedfileattributeview 获取流名称与大小,无需外部命令或 jni。
NTFS 文件系统支持一种常被忽视但功能强大的特性——替代数据流(Alternate Data Streams, ADS),它允许单个文件关联多个独立的数据流(如 file.txt:secret)。Java 从 JDK 7 起通过 java.nio.file.attribute.UserDefinedFileAttributeView 提供了对 ADS 的原生支持,但仅限 Windows NTFS 卷且需运行于 Windows 平台(其他文件系统或操作系统将返回空列表或抛出 UnsupportedOperationException)。
以下是一个完整、健壮的示例程序,用于递归(或非递归)列出指定目录下所有文件及其 ADS:
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.*;
import java.nio.file.attribute.UserDefinedFileAttributeView;
import java.util.stream.Stream;
public class ListAlternateDataStreams {
public static void main(String[] args) {
// 默认扫描当前目录;可替换为 Paths.get("C:\example")
Path root = Paths.get(".");
try (Stream<path> entries = Files.list(root)) {
entries.forEach(file -> {
if (!Files.isRegularFile(file) && !Files.isDirectory(file)) {
return; // 跳过符号链接、设备文件等
}
System.out.printf("%s [%s]%n",
Files.isDirectory(file) ? "[DIR]" : "[FILE]",
file.getFileName().toString());
// 尝试获取用户定义属性视图(即 ADS 视图)
UserDefinedFileAttributeView adsView =
Files.getFileAttributeView(file, UserDefinedFileAttributeView.class);
try {
// 列出所有 ADS 名称(不含主数据流 "$DATA")
for (String streamName : adsView.list()) {
long size;
try {
size = adsView.size(streamName);
} catch (IOException e) {
size = -1L; // 无法读取大小时标记为未知
}
System.out.printf(" → ADS: %-20s (%s bytes)%n",
streamName, size == -1 ? "unknown" : String.valueOf(size));
}
if (adsView.list().isEmpty()) {
System.out.println(" → No alternate data streams found.");
}
} catch (IOException e) {
// 权限不足、路径不存在或非 NTFS 卷均可能导致异常
System.err.printf(" ⚠️ Cannot access ADS for %s: %s%n",
file.getFileName(), e.getMessage());
}
System.out.println();
});
} catch (IOException e) {
throw new UncheckedIOException("Failed to list directory entries", e);
}
}
}</path>
✅ 关键要点说明:
- UserDefinedFileAttributeView.list() 返回的是 ADS 的名称列表(如 "secret" 对应 file.txt:secret),不包含主数据流(即默认的 "$DATA" 流,Java 不暴露该内置流)。
- adsView.size(name) 返回对应流的字节长度,对隐藏流(如 Zone.Identifier)同样有效。
- 此 API 不支持跨平台 ADS 操作:Linux/macOS 下调用 list() 总是返回空列表;若在非 NTFS 卷(如 FAT32、exFAT 或网络共享)上运行,将抛出 IOException 或静默失败。建议添加 FileSystem#isReadOnly() 和 FileStore#type() 检查以增强健壮性。
- 若需递归扫描整个目录树,请将 Files.list(p) 替换为 Files.walk(p, 10)(限制深度防循环),并配合 Files.isRegularFile() 过滤。
- 注意权限:某些系统级 ADS(如由 Windows Defender 创建)可能因 UAC 或访问控制策略导致 AccessDeniedException,应在 catch 块中妥善处理。
通过该方法,开发者可在纯 Java 环境中安全、高效地探测和审计 NTFS 上的替代数据流,适用于安全分析、取证工具或企业文件合规检查等场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











