Last active
August 29, 2015 14:23
-
-
Save svdamani/4e0839f380f76f904621 to your computer and use it in GitHub Desktop.
Calculate size of file system sub tree in Java (java.nio.files.*)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* File : FileSize.java | |
* Purpose : Concurrently process a filesystem sub-tree and calculate it's size | |
* Author : Shreevardhan | |
* Compilation : `javac FileSize.java` | |
* Execution : `java FileSize <path> <threads>` | |
*/ | |
import java.io.IOException; | |
import java.nio.file.*; | |
import java.nio.file.attribute.BasicFileAttributes; | |
import java.text.DecimalFormat; | |
import java.util.ArrayList; | |
import java.util.EnumSet; | |
import java.util.List; | |
import java.util.concurrent.ForkJoinPool; | |
import java.util.concurrent.RecursiveTask; | |
import java.util.concurrent.atomic.AtomicLong; | |
public class FileSize { | |
public static void main(String[] args) throws IOException { | |
Path path = Paths.get(System.getProperty("user.home")); | |
int threads = Runtime.getRuntime().availableProcessors(); | |
if (args.length >= 1) | |
path = Paths.get(args[0]); | |
if (args.length == 2) | |
threads = Integer.parseInt(args[1]); | |
long result = new FileSize().get(path, threads); | |
System.out.println(prettify(result) + "\t" + path); | |
} | |
static String prettify(Long size) { | |
if (size <= 0) return "0"; | |
int digits = (int) (Math.log10(size) / Math.log10(1024)); | |
String[] units = new String[] { "B", "KB", "MB", "GB" }; | |
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digits)) + units[digits]; | |
} | |
private Long get(Path path, int threads) { | |
ForkJoinPool pool = new ForkJoinPool(threads); | |
try { | |
return pool.invoke(new FileSizeTask(path)); | |
} finally { | |
pool.shutdown(); | |
} | |
} | |
} | |
class FileSizeTask extends RecursiveTask<Long> { | |
private Path path; | |
public FileSizeTask(Path path) { | |
this.path = path; | |
} | |
@Override | |
protected Long compute() { | |
List<FileSizeTask> tasks = new ArrayList<>(); | |
AtomicLong size = new AtomicLong(); | |
try { | |
Files.walkFileTree(path, EnumSet.of(FileVisitOption.FOLLOW_LINKS), | |
Integer.MAX_VALUE, new SimpleFileVisitor<Path>() { | |
@Override | |
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { | |
if (dir.equals(FileSizeTask.this.path)) { | |
size.addAndGet(attrs.size()); | |
return FileVisitResult.CONTINUE; | |
} | |
FileSizeTask task = new FileSizeTask(dir); | |
task.fork(); | |
tasks.add(task); | |
return FileVisitResult.SKIP_SUBTREE; | |
} | |
@Override | |
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { | |
size.addAndGet(attrs.size()); | |
return FileVisitResult.CONTINUE; | |
} | |
@Override | |
public FileVisitResult visitFileFailed(Path p, IOException e) { | |
System.err.println("Error: Cannot read " + p); | |
return FileVisitResult.CONTINUE; | |
} | |
}); | |
} | |
catch (IOException e) { | |
e.printStackTrace(); | |
} | |
for (FileSizeTask task : tasks) | |
size.addAndGet(task.join()); | |
return size.get(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment