计算一个文件大小的几种实现方式

1、串行计算

import java.io.File;

/**
 * 串行计算
 */
public class TotalFileSizeSequential {

    private long getTotalSizeOfFilesInDir(File file) {
        if(file.isFile())
            return file.length();

        long length = 0;
        File []children = file.listFiles();
        if(children != null)
            for(final File child : children) {
                length += getTotalSizeOfFilesInDir(child);
            }
        return length;
    }

    public static void main(String[] args) {
        final long start = System.nanoTime();
        final File file = new File("C:\\Windows");
        TotalFileSizeSequential total = new TotalFileSizeSequential();
        long size = total.getTotalSizeOfFilesInDir(file);
        final long end = System.nanoTime();
        System.out.println("total size:" + size);
        System.out.println("total token:"+(end - start) /1.0e9);
    }
}

2、线程协作,分子任务,启动新线程(目录不是很深的时候没问题)

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 每当扫描一个子任务的时候,就将子任务调度给其它线程
 * 目录不是很深的时候没问题
 *
 */
public class NativelyConcurrentTotalFileSize {

    private long getTotalSizeOfFile(File file) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService service = Executors.newFixedThreadPool(100);
        long size = getTotalSizeOfFilesInDir(service, file);
        return size;
    }

    private long getTotalSizeOfFilesInDir(final ExecutorService service, final File file) throws InterruptedException, ExecutionException, TimeoutException {
        if(file.isFile())
            return file.length();

        long size = 0;
        File []children = file.listFiles();
        if(children != null) {
            List<Future<Long>> futures = new ArrayList<Future<Long>>() ;
            for(final File child : children)
                futures.add(service.submit((new Callable<Long>() {
                        public Long call() throws Exception {
                            return getTotalSizeOfFilesInDir(service, child);
                        }
                    })
                ));

            for(Future<Long> future : futures) {
                size += future.get(10,TimeUnit.SECONDS);
            }
            return size;
        }
        return size;

    }

    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        final long start = System.nanoTime();
        final File file = new File("C:\\Windows");
        NativelyConcurrentTotalFileSize total = new NativelyConcurrentTotalFileSize();
        long size = total.getTotalSizeOfFile(file);
        final long end = System.nanoTime();
        System.out.println("total size:" + size);
        System.out.println("total token:"+(end - start) /1.0e9);
    }
}

3、解决第二种方法出现线程死锁超时的问题,每次计算文件夹中文件大小和保存子目录

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class ConcurrentTotalFileSize {

    /**
     * 保存子目录和文件大小(设计思想较为复杂)
     */
    class SubDirectoriesAndSize {
        public long size;
        public List<File> subDirectories;
        public SubDirectoriesAndSize(final long size, final List<File> subDirectories) {
            this.size = size;
            this.subDirectories = Collections.unmodifiableList(subDirectories);
        }
    }

    /**
     * 获取总大小
     */
    private long getTotalSizeOfFile(File file) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService service = Executors.newFixedThreadPool(100);
        long size = getTotalSizeOfFilesInDir(service, file);
        return size;
    }

    /**
     * 获取子目录和文件大小
     */
    private SubDirectoriesAndSize getSubDirectoriesAndSize(final File file) {
        long total = 0;
        List<File> subDirectories = new ArrayList<File>();
        if(file.isDirectory()) {
            File []children = file.listFiles();
            if(children != null)
                for(final File child : children) {
                    if(child.isFile())
                        total += child.length();
                    else
                        subDirectories.add(child);
                }
        }
        return new SubDirectoriesAndSize(total, subDirectories);
    }

    private long getTotalSizeOfFilesInDir(ExecutorService service, File file) throws InterruptedException, ExecutionException, TimeoutException {
        if(file.isFile())
            return file.length();

        long size = 0;
        List<File> directories = new ArrayList<File>();
        directories.add(file);
        try {
            while(!directories.isEmpty()) {
                List<Future<SubDirectoriesAndSize>> futures = new ArrayList<Future<SubDirectoriesAndSize>>() ;
                for(final File child : directories) {
                    futures.add(service.submit(new Callable<SubDirectoriesAndSize>() {

                        @Override
                        public SubDirectoriesAndSize call() throws Exception {
                            return getSubDirectoriesAndSize(child);

                        }
                    }));
                }
                directories.clear();//清除原有子目录

                for(Future<SubDirectoriesAndSize> future : futures) {
                    size += future.get().size;
                    directories.addAll(future.get(100,TimeUnit.SECONDS).subDirectories);
                }
            }
        } finally {
            service.shutdown();
        }

        return size;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        final long start = System.nanoTime();
        final File file = new File("C:\\Windows");//文件夹路径自定
        ConcurrentTotalFileSize total = new ConcurrentTotalFileSize();
        long size = total.getTotalSizeOfFile(file);
        final long end = System.nanoTime();
        System.out.println("total size:" + size);
        System.out.println("total token:"+(end - start) /1.0e9);
    }

}

4、数据交换,使用ArrayBlockingQueue,在线程间互发多组数据

import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 数据交换
 * 使用ArrayBlockingQueue,在线程间互发多组数据
 */
public class ConcurrentTotalFileSizeWQueue {

    private ExecutorService service;
    final private BlockingQueue<Long> fileSizes = new ArrayBlockingQueue<Long>(500);//简单的阻塞队列
    final private AtomicLong pendingFileVisits = new AtomicLong();

    private long getTotalSizeOfFile(File file) throws InterruptedException {
        service = Executors.newFixedThreadPool(100);
        try {
            startExploreFile(file);
            long totalSize = 0;
            while(pendingFileVisits.get() > 0 || fileSizes.size() > 0) {
                final long size = fileSizes.poll(10, TimeUnit.SECONDS);
                totalSize += size;
            }
            return totalSize;
        } finally {
            service.shutdown();
        }
    }

    private void startExploreFile(final File file) {
        pendingFileVisits.incrementAndGet();
        service.execute(new Runnable() {

            public void run() {
                exploreDir(file);
            }

        });
    }

    private void exploreDir(final File file) {
        long fileSize = 0;
        if(file.isFile())
            fileSize = file.length();
        else {
            File[] children = file.listFiles();
            if(children != null) {
                for(File child : children) {
                    if(child.isFile())
                        fileSize += child.length();
                    else
                        startExploreFile(child);
                }
            }
        }

        try {
            fileSizes.put(fileSize);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        pendingFileVisits.decrementAndGet();
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        final long start = System.nanoTime();
        final File file = new File("C:\\Windows");//文件夹路径自定
        ConcurrentTotalFileSizeWQueue total = new ConcurrentTotalFileSizeWQueue();
        long size = total.getTotalSizeOfFile(file);
        final long end = System.nanoTime();
        System.out.println("total size:" + size);
        System.out.println("total token:"+(end - start) /1.0e9);
    }
}

5、CountDownLatch实现,不返回结果,共享状态,代码简洁

/**
 * CountDownLatch的使用
 * 线程不再返回一个结果,AtomicLong提供了更改并取回一个简单long型变量值的线程安全方法
 * java.util.concurrent.atomic包中定义的其它原子操作类对于处理单个共享数据的值来说非常有用
 */
public class ConcurrentTotalSizeWLatch {

    private ExecutorService service;
    private AtomicLong pendingFileVisits = new AtomicLong();//作用是提供当前当前待访问的文件(或子目录)的数量
    private AtomicLong totalSize = new AtomicLong();//计算大小
    private CountDownLatch  latch = new CountDownLatch(1);
    private long getTotalSizeOfFile(File file) {
        service = Executors.newFixedThreadPool(100);
        pendingFileVisits.incrementAndGet();
        updateTotalSizeOfFileInDir(file);
        try {
            latch.await(100, TimeUnit.SECONDS);//当前线程等待直到latch减为0,除非线程被打断或超时
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            service.shutdown();
        }
        return totalSize.longValue();
    }

    private void updateTotalSizeOfFileInDir(File file) {
        long fileSize = 0;
        if(file.isFile())
            fileSize = file.length();

        if(file.isDirectory()) {
            File[] children = file.listFiles();
            if(children != null) {
                for(final File child : children) {
                    if(file.isFile())
                        fileSize += child.length();
                    else {
                        pendingFileVisits.incrementAndGet();
                        service.execute(new Runnable() {
                            public void run() {
                                updateTotalSizeOfFileInDir(child);
                            }
                        });
                    }

                }
            }
        }
        totalSize.addAndGet(fileSize);

        if(pendingFileVisits.decrementAndGet() == 0) latch.countDown();//释放线程闩
    }

    public static void main(String[] args) {
        final long start = System.nanoTime();
        final File file = new File("C:\\Windows");
        ConcurrentTotalSizeWLatch total = new ConcurrentTotalSizeWLatch();
        long size = total.getTotalSizeOfFile(file);
        final long end = System.nanoTime();
        System.out.println("total size:" + size);
        System.out.println("total token:"+(end - start) /1.0e9);
    }

此学习内容来自<Java虚拟机并发编程>一书。

时间: 2024-08-09 06:27:04

计算一个文件大小的几种实现方式的相关文章

python 计算等差数列和的两种循环方式

计算 1~100 的和 5050 while 循环: i, s = 0, 0 while i < 101: s += i i += 1 print(s) for 循环: s = 0 for i in range(101): s += i print(s) 原文地址:https://www.cnblogs.com/shanger/p/12180784.html

Android一个应用多个图标的几种实现方式

本文标签: Android activity-alias 新需求我的应用将有多个ICON入口..最终选择了 activity-alias , 其实实现多图标有好几种方式 1. 多Activity + intent-filter方式 因为launcher会扫描app中含有以下intent-filter属性的标签, 有的话就会将其添加到桌面.所以只要在你想添加到桌面的activity下加上以下标签即可. <intent-filter> <action android:name="a

计算一个目录文件大小方法

<?php $dirfile='../hnb'; /** *计算一个目录文件大小方法 *$dirfile:传入文件目录名 **/ function dirSize($dirfile) { $dir_size=0; if($handle[email protected]opendir($dirfile)) { while($filename=readdir($handle)) { if($filename!='.' && $filename!='..') { $subfile=$dir

用1,2,3,4四个数字随意搭配组成一个三位数且两两互不相同,一共有几种搭配方式并输出

1 public class ZuHe{//1 2 3 4随意组合为一个三位数问一共有多少种组合方式,且三个数字互不相同 2 public static void main(String[] args){ 3 int x=0; 4 for(int i =1;i<=4;i++){ 5 for(int j=1;j<=4;j++){ 6 int k=1; 7 while(k<=4){ 8 int s=i*100+j*10+k; 9 if(s/100!=s/10%10&&s/10

shell调用另一个脚本的三种方式fork/exec/source

exec和source都属于bash内部命令(builtins commands),在bash下输入man exec或man source可以查看所有的内部命令信息. bash shell的命令分为两类:外部命令和内部命令.外部命令是通过系统调用或独立的程序实现的,如sed.awk等等.内部命令是由特殊的文件格式(.def)所实现,如cd.history.exec等等. 在说明exe和source的区别之前,先说明一下fork的概念. fork是linux的系统调用,用来创建子进程(child

php网站常见的几种攻击方式(转)

针对 PHP 的网站主要存在下面几种攻击方式::1.命令注入(Command Injection)2.eval 注入(Eval Injection)3.客户端脚本攻击(Script Insertion)4.跨网站脚本攻击(Cross Site Scripting, XSS)5.SQL 注入攻击(SQL injection)6.跨网站请求伪造攻击(Cross Site Request Forgeries, CSRF)7.Session 会话劫持(Session Hijacking)8.Sessio

Redis两种持久化方式(RDB&amp;AOF)

爬虫和转载请注明原文地址;博客园蜗牛:http://www.cnblogs.com/tdws/p/5754706.html Redis所需内存 超过可用内存怎么办 Redis修改数据多线程并发—Redis并发锁 windows下redis基础操作与主从复制 从而 数据备份和读写分离 Redis两种持久化方式(RDB&AOF) Redis的持久化过程中并不需要我们开发人员过多的参与,我们要做的是什么呢?除了深入了解RDB和AOF的作用原理,剩下的就是根据实际情况来制定合适的策略了,再复杂一点,也就

LVS三种工作方式八种算法

一.集群简介 什么是集群 计算机集群简称集群是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作.在某种意义上,他们可以被看作是一台计算机.集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式.集群计算机通常用来改进单个计算机的计算速度和/或可靠性.一般情况下集群计算机比单个计算机,比如工作站或超级计算机性能价格比要高得多. 集群就是一组独立的计算机,通过网络连接组合成一个组合来共同完一个任务 LVS在企业架构中的位置: 以上的

java 定时器的几种实现方式以及 配置参数的说明

2.java中常见的定时器 1)借助Java.util.Timer来实现 2)OpenSymphony社区提供的Quartz来实现 3.介绍Timer 利用Timer开发定时任务是主要分为两个步骤: 1)创建定时任务类 示例代码: package org.lzstone.action import java.util.TimeTask public class LzstoneTimeTask extends TimeTask{ public void run(){ //执行的定时器任务 } }