1 普通方式实现
package org.test;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FileCounterRecursive {
/**
* 递归统计文件数量
* @param directoryPath 目录路径
* @return 文件总数
*/
public static int countFilesRecursive(String directoryPath) {
File directory = new File(directoryPath);
if (!directory.exists()) {
System.err.println("目录不存在: " + directoryPath);
return 0;
}
if (!directory.isDirectory()) {
System.err.println("路径不是目录: " + directoryPath);
return 0;
}
return countFiles(directory);
}
/**
* 递归核心方法
*/
private static int countFiles(File directory) {
int count = 0;
File[] files = directory.listFiles();
if (files == null) {
return 0;
}
for (File file : files) {
if (file.isFile()) {
count++;
} else if (file.isDirectory()) {
count += countFiles(file); // 递归调用
}
}
return count;
}
/**
* 递归统计并获取文件列表
*/
public static List<File> getAllFilesRecursive(String directoryPath) {
List<File> fileList = new ArrayList<>();
File directory = new File(directoryPath);
if (directory.exists() && directory.isDirectory()) {
collectFiles(directory, fileList);
}
return fileList;
}
/**
* 递归收集文件
*/
private static void collectFiles(File directory, List<File> fileList) {
File[] files = directory.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isFile()) {
fileList.add(file);
} else if (file.isDirectory()) {
collectFiles(file, fileList);
}
}
}
public static void main(String[] args) {
String path = "D:/src";
System.out.println("=== 递归方式统计文件 ===");
long startTime = System.currentTimeMillis();
int totalFiles = countFilesRecursive(path);
long endTime = System.currentTimeMillis();
System.out.println("总文件数: " + totalFiles);
System.out.println("统计耗时: " + (endTime - startTime) + "ms");
// 获取文件列表
List<File> files = getAllFilesRecursive(path);
System.out.println("文件列表数量验证: " + files.size());
// 按类型统计
System.out.println("\n=== 按文件类型统计 ===");
countByExtension(files);
}
/**
* 按文件扩展名统计
*/
private static void countByExtension(List<File> files) {
Map<String, Integer> extensionCount = new HashMap<>();
for (File file : files) {
String fileName = file.getName();
int dotIndex = fileName.lastIndexOf('.');
if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
String extension = fileName.substring(dotIndex + 1).toLowerCase();
extensionCount.put(extension, extensionCount.getOrDefault(extension, 0) + 1);
} else {
extensionCount.put("无扩展名", extensionCount.getOrDefault("无扩展名", 0) + 1);
}
}
// 按数量排序
List<Map.Entry<String, Integer>> sortedList = new ArrayList<>(extensionCount.entrySet());
sortedList.sort((a, b) -> b.getValue().compareTo(a.getValue()));
for (Map.Entry<String, Integer> entry : sortedList) {
System.out.printf("%-10s: %d 个文件%n", entry.getKey(), entry.getValue());
}
}
}
=== 递归方式统计文件 ===
总文件数: 7718
统计耗时: 172ms
文件列表数量验证: 7718
=== 按文件类型统计 ===
java : 7701 个文件
h : 9 个文件
c : 8 个文件
2 普通方式(栈结构)实现
package org.test;
import java.util.*;
import java.io.File;
import java.util.Stack;
public class FileCounterStack {
/**
* 使用栈的非递归方式统计文件数量
*/
public static int countFilesWithStack(String directoryPath) {
File rootDir = new File(directoryPath);
if (!rootDir.exists() || !rootDir.isDirectory()) {
System.err.println("无效的目录路径: " + directoryPath);
return 0;
}
int fileCount = 0;
Stack<File> stack = new Stack<>();
stack.push(rootDir);
while (!stack.isEmpty()) {
File currentDir = stack.pop();
File[] files = currentDir.listFiles();
if (files == null) {
continue;
}
for (File file : files) {
if (file.isFile()) {
fileCount++;
} else if (file.isDirectory()) {
stack.push(file); // 将子目录压入栈中
}
}
}
return fileCount;
}
/**
* 使用栈获取所有文件列表
*/
public static List<File> getAllFilesWithStack(String directoryPath) {
List<File> fileList = new ArrayList<>();
File rootDir = new File(directoryPath);
if (!rootDir.exists() || !rootDir.isDirectory()) {
return fileList;
}
Stack<File> stack = new Stack<>();
stack.push(rootDir);
while (!stack.isEmpty()) {
File currentDir = stack.pop();
File[] files = currentDir.listFiles();
if (files == null) {
continue;
}
for (File file : files) {
if (file.isFile()) {
fileList.add(file);
} else if (file.isDirectory()) {
stack.push(file);
}
}
}
return fileList;
}
/**
* 统计并显示目录结构
*/
public static void displayDirectoryStructure(String directoryPath) {
File rootDir = new File(directoryPath);
if (!rootDir.exists() || !rootDir.isDirectory()) {
System.out.println("目录不存在: " + directoryPath);
return;
}
System.out.println("\n=== 目录结构 ===");
System.out.println(rootDir.getAbsolutePath());
Stack<FileWithLevel> stack = new Stack<>();
stack.push(new FileWithLevel(rootDir, 0));
while (!stack.isEmpty()) {
FileWithLevel current = stack.pop();
File currentDir = current.file;
int level = current.level;
File[] files = currentDir.listFiles();
if (files == null || files.length == 0) {
continue;
}
// 先处理目录,以便正确显示层级
List<File> directories = new ArrayList<>();
List<File> fileList = new ArrayList<>();
for (File file : files) {
if (file.isDirectory()) {
directories.add(file);
} else {
fileList.add(file);
}
}
// 将目录压入栈中(逆序,以便正序显示)
for (int i = directories.size() - 1; i >= 0; i--) {
stack.push(new FileWithLevel(directories.get(i), level + 1));
}
// 显示当前目录下的文件
for (File file : fileList) {
printWithIndent(file.getName(), level + 1);
}
}
}
private static void printWithIndent(String name, int level) {
StringBuilder indent = new StringBuilder();
for (int i = 0; i < level; i++) {
indent.append("│ ");
}
System.out.println(indent + "├── " + name);
}
static class FileWithLevel {
File file;
int level;
FileWithLevel(File file, int level) {
this.file = file;
this.level = level;
}
}
public static void main(String[] args) {
String path = "D:/src";
System.out.println("=== 栈方式统计文件 ===");
long startTime = System.currentTimeMillis();
int totalFiles = countFilesWithStack(path);
long endTime = System.currentTimeMillis();
System.out.println("总文件数: " + totalFiles);
System.out.println("统计耗时: " + (endTime - startTime) + "ms");
// 显示目录结构
displayDirectoryStructure(path);
}
}
... 上层忽略
│ │ │ │ │ ├── ParserAdapter.java
│ │ │ │ │ ├── ParserFactory.java
│ │ │ │ │ ├── SecuritySupport.java
│ │ │ │ │ ├── XMLFilterImpl.java
│ │ │ │ │ ├── XMLReaderAdapter.java
│ │ │ │ │ ├── XMLReaderFactory.java
3 Java 8+ Files API
package org.test;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
public class FileCounterJava8 {
/**
* 使用Java 8的Files.walk方法
*/
public static long countFilesWithWalk(String directoryPath) throws IOException {
Path startPath = Paths.get(directoryPath);
if (!Files.exists(startPath) || !Files.isDirectory(startPath)) {
return 0;
}
// 使用try-with-resources确保流关闭
try (Stream<Path> stream = Files.walk(startPath)) {
return stream
.filter(Files::isRegularFile) // 只统计普通文件
.count();
}
}
/**
* 使用FileVisitor接口
*/
public static int countFilesWithFileVisitor(String directoryPath) throws IOException {
Path startPath = Paths.get(directoryPath);
AtomicInteger counter = new AtomicInteger(0);
Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (attrs.isRegularFile()) {
counter.incrementAndGet();
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
System.err.println("无法访问文件: " + file + " - " + exc.getMessage());
return FileVisitResult.CONTINUE; // 继续遍历其他文件
}
});
return counter.get();
}
/**
* 按文件大小统计
*/
public static Map<String, Long> countFilesBySizeRange(String directoryPath) throws IOException {
Path startPath = Paths.get(directoryPath);
Map<String, Long> sizeRanges = new LinkedHashMap<>();
// 初始化大小范围
sizeRanges.put("0-1KB", 0L);
sizeRanges.put("1KB-1MB", 0L);
sizeRanges.put("1MB-10MB", 0L);
sizeRanges.put("10MB-100MB", 0L);
sizeRanges.put("100MB-1GB", 0L);
sizeRanges.put(">1GB", 0L);
try (Stream<Path> stream = Files.walk(startPath)) {
stream.filter(Files::isRegularFile)
.forEach(path -> {
try {
long size = Files.size(path);
String range = getSizeRange(size);
sizeRanges.put(range, sizeRanges.get(range) + 1);
} catch (IOException e) {
System.err.println("无法获取文件大小: " + path);
}
});
}
return sizeRanges;
}
private static String getSizeRange(long size) {
if (size < 1024) return "0-1KB";
else if (size < 1024 * 1024) return "1KB-1MB";
else if (size < 10 * 1024 * 1024) return "1MB-10MB";
else if (size < 100 * 1024 * 1024) return "10MB-100MB";
else if (size < 1024 * 1024 * 1024) return "100MB-1GB";
else return ">1GB";
}
/**
* 查找重复文件(根据文件名和大小)
*/
public static Map<String, List<Path>> findDuplicateFiles(String directoryPath) throws IOException {
Path startPath = Paths.get(directoryPath);
Map<String, List<Path>> duplicateMap = new HashMap<>();
try (Stream<Path> stream = Files.walk(startPath)) {
stream.filter(Files::isRegularFile)
.forEach(path -> {
String key = path.getFileName().toString() + "_" + getFileSize(path);
duplicateMap.computeIfAbsent(key, k -> new ArrayList<>()).add(path);
});
}
// 过滤出重复的文件
duplicateMap.entrySet().removeIf(entry -> entry.getValue().size() < 2);
return duplicateMap;
}
private static String getFileSize(Path path) {
try {
long size = Files.size(path);
if (size < 1024) return size + "B";
else if (size < 1024 * 1024) return (size / 1024) + "KB";
else return (size / (1024 * 1024)) + "MB";
} catch (IOException e) {
return "unknown";
}
}
public static void main(String[] args) {
String path = "D:/src";
System.out.println("=== Java 8 Files API 统计 ===");
try {
// 方法1: Files.walk
long startTime = System.currentTimeMillis();
long totalFiles = countFilesWithWalk(path);
long endTime = System.currentTimeMillis();
System.out.println("Files.walk 统计结果: " + totalFiles + " 个文件");
System.out.println("耗时: " + (endTime - startTime) + "ms");
// 方法2: FileVisitor
startTime = System.currentTimeMillis();
int visitorCount = countFilesWithFileVisitor(path);
endTime = System.currentTimeMillis();
System.out.println("\nFileVisitor 统计结果: " + visitorCount + " 个文件");
System.out.println("耗时: " + (endTime - startTime) + "ms");
// 按大小统计
System.out.println("\n=== 按文件大小统计 ===");
Map<String, Long> sizeRanges = countFilesBySizeRange(path);
for (Map.Entry<String, Long> entry : sizeRanges.entrySet()) {
System.out.printf("%-12s: %d 个文件%n", entry.getKey(), entry.getValue());
}
// 查找重复文件
System.out.println("\n=== 重复文件检查 ===");
Map<String, List<Path>> duplicates = findDuplicateFiles(path);
System.out.println("发现 " + duplicates.size() + " 组重复文件");
for (Map.Entry<String, List<Path>> entry : duplicates.entrySet()) {
System.out.println("\n重复组: " + entry.getKey());
for (Path p : entry.getValue()) {
System.out.println(" " + p);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
=== Java 8 Files API 统计 ===
Files.walk 统计结果: 7718 个文件
耗时: 218ms
FileVisitor 统计结果: 7718 个文件
耗时: 32ms
=== 按文件大小统计 ===
0-1KB : 923 个文件
1KB-1MB : 6795 个文件
1MB-10MB : 0 个文件
10MB-100MB : 0 个文件
100MB-1GB : 0 个文件
>1GB : 0 个文件
=== 重复文件检查 ===
发现 109 组重复文件
4 递归方式