/**
*
* Funf: Open Sensing Framework
* Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
* Acknowledgments: Alan Gardner
* Contact: nadav@media.mit.edu
*
* This file is part of Funf.
*
* Funf is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Funf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Funf. If not, see <http://www.gnu.org/licenses/>.
*
*/
package edu.mit.media.funf.storage;
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import android.os.StatFs;
/**
* Cleans unneeded files from directories
*/
public interface DirectoryCleaner {
public void clean(File directory);
public static class KeepAll implements DirectoryCleaner {
@Override
public void clean(File directory) {}
}
/**
* Keep only the most recent specified amount of files
*
*/
public static class KeepMostRecent implements DirectoryCleaner {
private final int numToKeep;
public KeepMostRecent(int numToKeep) {
this.numToKeep = numToKeep;
}
@Override
public void clean(File directory) {
if (directory.isDirectory()) {
File[] files = directory.listFiles();
if (files != null && files.length > numToKeep) {
// Sort descending by last modified time
Arrays.sort(files, new DescendingByLastModifiedComaparator());
// Delete all except the first numToKeep files
for (int i=numToKeep; i<files.length; i++) {
files[i].delete();
}
}
}
}
}
/**
* Only Keep files for a certain length of time
*
*/
public static class KeepForLengthOfTime implements DirectoryCleaner {
private final long millisToKeep;
public KeepForLengthOfTime(long millisToKeep) {
this.millisToKeep = millisToKeep;
}
@Override
public void clean(File directory) {
if (directory.isDirectory()) {
File[] files = directory.listFiles();
if (files != null) {
long now = System.currentTimeMillis();
for (File file : files) {
if ((now - file.lastModified()) > millisToKeep) {
file.delete();
}
}
}
}
}
}
/**
* Keeps the total size of all files in the directory under the number of bytes specified
*/
public static class KeepUnderStorageLimit implements DirectoryCleaner {
private final long maxBytesToKeep;
public KeepUnderStorageLimit(long maxBytesToKeep) {
this.maxBytesToKeep = maxBytesToKeep;
}
@Override
public void clean(File directory) {
if (directory.isDirectory()) {
File[] files = directory.listFiles();
long bytesToDelete = size(directory) - maxBytesToKeep;
if (bytesToDelete > 0) {
Arrays.sort(files, new DescendingByLastModifiedComaparator());
for (int i=files.length; i>=0; i--) {
if (bytesToDelete > 0) {
bytesToDelete -= size(files[i]);
files[i].delete();
}
}
}
}
}
/**
* Calculate the size of the file or directory recursively.
* @param file
*/
private long size(File file) {
if (file.isDirectory()) {
long bytes = 0;
for (File childFile : file.listFiles()) {
bytes += size(childFile);
}
return bytes;
} else {
return file.length();
}
}
}
/**
* Cleans files to use only a certain percentage of the disk that is free
*/
public static class KeepUnderPercentageOfDiskFree implements DirectoryCleaner {
private final double percentageOfDiskFree;
private final long minBytesToKeep;
public KeepUnderPercentageOfDiskFree(double percentageOfDiskFree, long minBytesToKeep) {
assert percentageOfDiskFree > 0 && percentageOfDiskFree <= 1;
this.percentageOfDiskFree = percentageOfDiskFree;
this.minBytesToKeep = minBytesToKeep;
}
@Override
public void clean(File directory) {
StatFs stat = new StatFs(directory.getAbsolutePath());
long bytesAvailable = (long)stat.getAvailableBlocks() * (long)stat.getBlockSize();
long bytesToKeep = Math.max((long)(bytesAvailable * percentageOfDiskFree), minBytesToKeep);
new KeepUnderStorageLimit(bytesToKeep).clean(directory);
}
}
/**
* Applies all of the cleaning strategies to the directory
*/
public static class CompositeDirectoryCleaner implements DirectoryCleaner {
private final DirectoryCleaner[] cleaners;
public CompositeDirectoryCleaner(DirectoryCleaner... cleaners) {
this.cleaners = cleaners;
}
@Override
public void clean(File directory) {
for(DirectoryCleaner cleaner : cleaners) {
cleaner.clean(directory);
}
}
}
static class DescendingByLastModifiedComaparator implements Comparator<File> {
@Override
public int compare(File file0, File file1) {
return Long.valueOf(file1.lastModified()).compareTo(
file0.lastModified());
}
}
}