ETJava Beta | Java    注册   登录
  • java统计文件数量多方式实现 - 普通方式

    发表于 2025-12-02 08:42:43     阅读(52)     博客类别:J2SE

    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 递归方式