package com.diguage.truman.concurrent; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.NavigableSet; import java.util.Objects; import java.util.TreeMap; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author D瓜哥, https://www.diguage.com/ * @since 2020-04-22 20:39 */ public class FilesSpy { public static void main(String[] args) { ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors()); String homePath = System.getProperty("user.home"); TreeNode root = new TreeNode(homePath); pool.execute(new FileSizeTask(root)); } public static class FileSizeTask extends RecursiveTask<Integer> { private final TreeNode root; public FileSizeTask(TreeNode root) { this.root = root; } @Override protected Integer compute() { return null; } } public static class TreeNode { private final TreeNode parent; private final File file; private final String absolutePath; private final String name; private AtomicLong size = new AtomicLong(0); private Comparator<TreeNode> comparator = Comparator.comparingLong(TreeNode::length); private TreeMap<TreeNode, TreeNode> pathToNode; private ReentrantReadWriteLock lock; private ReentrantReadWriteLock.WriteLock writeLock; private ReentrantReadWriteLock.ReadLock readLock; public TreeNode(String absolutePath) { this(absolutePath, null); } public TreeNode(String absolutePath, TreeNode parent) { this(new File(absolutePath), parent); } public TreeNode(File file, TreeNode parent) { this.parent = parent; this.absolutePath = file.getAbsolutePath(); this.file = file; this.name = this.file.getName(); if (this.file.isFile()) { long bytes = file.length(); long len = 1; if (bytes > 1024) { len = (bytes & (1024 - 1)) == 0 ? bytes / 1024 : bytes / 1024 + 1; size = new AtomicLong(len); } } else { this.lock = new ReentrantReadWriteLock(); this.writeLock = lock.writeLock(); this.readLock = lock.readLock(); pathToNode = new TreeMap<>(comparator); } } public List<File> getSubfiles() { try { readLock.lock(); if (Objects.isNull(pathToNode) || pathToNode.isEmpty()) { return Collections.emptyList(); } NavigableSet<TreeNode> treeNodes = pathToNode.navigableKeySet(); List<File> result = new ArrayList<>(treeNodes.size()); for (TreeNode node : treeNodes) { result.add(node.getFile()); } return result; } finally { readLock.unlock(); } } public void add(File file) { if (Objects.isNull(file) || !file.exists()) { throw new IllegalArgumentException("文件必须存在!"); } if (isFile()) { throw new UnsupportedOperationException("文件没有子目录!"); } if (!file.getAbsolutePath().startsWith(getAbsolutePath())) { throw new IllegalArgumentException("只能添加子目录!"); } try { writeLock.lock(); TreeNode node = new TreeNode(file, this); if (contains(node)) { return; } pathToNode.put(node, node); // 更新大小 TreeNode temp = this; while (Objects.nonNull(temp)) { temp.getSize().getAndAdd(node.length()); temp = temp.parent; } } finally { writeLock.unlock(); } } public File getFile() { return file; } public boolean isFile() { return file.isFile(); } public boolean isPath() { return !isFile(); } public String getAbsolutePath() { return absolutePath; } public long length() { return size.get(); } public AtomicLong getSize() { return this.size; } public boolean contains(TreeNode treeNode) { try { readLock.lock(); return pathToNode.containsKey(treeNode); } finally { readLock.unlock(); } } public String getName() { return name; } public TreeNode getParent() { return parent; } } }