OBJECTIVE // Due to a couple projects that I had coded for work that involved large volumes of image captures, the hard drive of my computer was starting to fill up fast. Though I was fairly certain where this huge pockets of data storage were, with 230 GB on my computer, I figured there had to be other areas I didn’t know about. In Window Explorer, you can see file size, but it doesn’t let you view the size of the folders and all the files that they contain, and even though I love numbers, processing all of that in my head is more tedious than I wanted. What I needed was a heat map that would allow you to quickly navigate through the file structure and identify where heavy pockets of data were being stored.
The solution was named OstrichNest because if you’re looking at a large tree that is leaning over and you are trying to find where all the birds are sitting and causing the tree to bend, if you find an ostrich on a branch (for some bizarre reason), you’ve found your problem.
THE PROGRAM// The applet was written in Processing and was pretty straightforward. When you launch the program, it asks you to select a rootfolder, which allows you avoid processing the data in your entire computer, which can be very time consuming. The program recreates the tree structure and uses a depth first search to set values for all the folders based on the weight of their branches (sub-folders) and leaves (files). I am still not sure whether a uniform mono-color gradient mapping the folder weight directly with brightness is the best way to represent the data. Perhaps there could be different colors for different thresholds or maybe I would learn something by looking at the weight of branches without any children. Regardless, the program lead me right to some data intensive pockets of my computer, including the time lapse photos as I expected, so it seems to be pretty effective.
You can download the source files and an executable of the applet here on Github.
When you click on a folder, it enters that directory, as long as there are more folders inside. Once you reach a folder with only files in it, nothing happens when you click on it. The backspace button brings you to the directory above and double clicking the folder opens it up in Windows Explorer so you can view what files it contains.
SOME CODE//
//*********************************************************************************
// This app is used to visualize and navigate a file structure to
// determine where there is an excess of data being stored.
//
// Written by Jack Boland, jcboland91@gmail.com
//
// * —————————————————————————-
// * “THE BEER-WARE LICENSE” (Revision 42):
// * <jcboland91@gmail.com> wrote this file. As long as you retain this notice you
// * can do whatever you want with this stuff. If we meet some day, and you think
// * this stuff is worth it, you can buy me a beer in return. (Poul-Henning Kamp)
// * —————————————————————————-
//
//**********************************************************************************
import java.awt.*;
String rootFolder;
Folder root;
Folder currentFolder;
Interface appInter = new Interface();
boolean treeConstructed = false;
int border = 5;
int dots = 1;void setup(){
size(800, 800);
background(255);fill(100);
stroke(100);
textSize(25);
textAlign(CENTER, CENTER);
text(“Please wait while your \n computer is analyzed”, width/2, height/2);
thread(“createTree”);}
void draw(){
if(treeConstructed != true){
background(255);
fill(100);
stroke(100);
textSize(20);
textAlign(CENTER, CENTER);
text(“Please wait while your \n computer is analyzed”, width/2, height/2);
if(dots == 1){
ellipse(width/2 – 90, height/2 + 50, 5, 5);
}
if(dots == 2){
ellipse(width/2 – 90, height/2 + 50, 5, 5);
ellipse(width/2 – 30, height/2 + 50, 5, 5);
}
if(dots == 3){
ellipse(width/2 – 90, height/2 + 50, 5, 5);
ellipse(width/2 – 30, height/2 + 50, 5, 5);
ellipse(width/2 + 30, height/2 + 50, 5, 5);
}
if(dots == 4){
ellipse(width/2 – 90, height/2 + 50, 5, 5);
ellipse(width/2 – 30, height/2 + 50, 5, 5);
ellipse(width/2 + 30, height/2 + 50, 5, 5);
ellipse(width/2 + 90, height/2 + 50, 5, 5);
}dots++;
if(dots == 5){
dots = 1;
}
delay(500);}
else{
appInter.display();
}}
void mouseReleased(){
if(mouseEvent.getClickCount()==2){
println(“Double Click”);
Button tempButton = appInter.checkButtonPress();
if(tempButton != null){
File file = new File(tempButton.getLocation());
Desktop desktop = Desktop.getDesktop();
try{
desktop.open(file);
}
catch(IOException e){
println(“Cannot Open Location”);
}
}
}
else{
Button tempButton = appInter.checkButtonPress();
println(“Mouse Pressed”);
if(tempButton != null){
if(tempButton.getFolder().getChildren().size() != 0){
currentFolder = tempButton.getFolder();
createButtons();
println(tempButton.getLocation());
}
}
}}
void keyPressed(){
if(key == BACKSPACE){
if(currentFolder.getParent() != null){
currentFolder = currentFolder.getParent();
createButtons();
println(currentFolder.getLocation());
println(currentFolder.getWeight());
}}
}
void createButtons(){
appInter.clearButtons();
ArrayList<Folder> currChildren = currentFolder.getChildren();
//long totalWeight = currentFolder.getWeight();
int totalChildren = currChildren.size();
int num = 0;//Button(int widthBut, int heightBut, int xpos, int ypos, color buttonColor, String text)
for(Folder temp : currChildren){float ratio = (float)temp.getWeight()/(float)currentFolder.getWeight();
int butHeight = (height – border*(totalChildren + 1))/totalChildren;
float value = ratio * 255;
color butColor = color(250, 109, 43, value+100);
Button newButton = new Button(width – border*2, butHeight, width/2,
border + butHeight/2 + (butHeight+border)*num, butColor, temp.getName());
newButton.setFolder(temp);
appInter.addButton(newButton);
println(newButton.text + “//” + temp.getWeight());
num++;
}
}
void createTree(){
// First – prompt the user for the root folder.
selectFolder(“Select the root folder:”, “folderSelection”);
while(rootFolder == null){
}
currentFolder = new Folder(rootFolder);
constructTree(currentFolder);long totalWeight = 0;
ArrayList<Folder> grandChildren = currentFolder.getChildren();
if(grandChildren.size() > 0){
for(Folder grandChild : grandChildren){
totalWeight += grandChild.getWeight();
//println(totalWeight);
}
}ArrayList<Leaf> grandChildrenLeaf = currentFolder.getLeaves();
if(grandChildrenLeaf.size() > 0){
for(Leaf grandChildLeaf : grandChildrenLeaf){
totalWeight += grandChildLeaf.getWeight();
}
}
currentFolder.setWeight(totalWeight);
createButtons();
treeConstructed = true;}
void constructTree(Folder tempFolder){
File currFile = new File(tempFolder.getLocation());
String[] currChildren = currFile.list();if(currChildren != null){
if(currChildren.length > 0){
for(String tempChild : currChildren){
File tempFile = new File(tempFolder.getLocation() + “\\” + tempChild);
if(tempFile.isDirectory()){
Folder childFolder = new Folder(tempFolder.getLocation() + “\\” + tempChild);
childFolder.setParent(tempFolder);
tempFolder.addChild(childFolder);
constructTree(childFolder);long totalWeight = 0;
ArrayList<Folder> grandChildren = childFolder.getChildren();
if(grandChildren.size() > 0){
for(Folder grandChild : grandChildren){
totalWeight += grandChild.getWeight();
//println(totalWeight);
}
}ArrayList<Leaf> grandChildrenLeaf = childFolder.getLeaves();
if(grandChildrenLeaf.size() > 0){
for(Leaf grandChildLeaf : grandChildrenLeaf){
totalWeight += grandChildLeaf.getWeight();
}
}
childFolder.setWeight(totalWeight);}
else{
Leaf tempLeaf = new Leaf(tempFolder.getLocation() + “\\” + tempChild);
File leafFile = new File(tempLeaf.getLocation());
tempLeaf.setParent(tempFolder);
tempLeaf.setWeight(leafFile.length());
//println(leafFile.length());
tempFolder.addLeaf(tempLeaf);
//println(tempLeaf.getLocation());
}
}
}
}
}
// Called once an action occurs using the folder selection prompt
void folderSelection(File selection){
rootFolder = selection.getAbsolutePath();
println(“Root folder selected: ” + rootFolder);
}