package cn.qqtheme.framework.util;
import android.support.annotation.IntDef;
import android.webkit.MimeTypeMap;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.regex.Pattern;
/**
* 文件处理
* <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
*
* @author 李玉江[QQ:1023694760]
* @since 2014-4-18
*/
public final class FileUtils {
public static final int BY_NAME_ASC = 0;
public static final int BY_NAME_DESC = 1;
public static final int BY_TIME_ASC = 2;
public static final int BY_TIME_DESC = 3;
public static final int BY_SIZE_ASC = 4;
public static final int BY_SIZE_DESC = 5;
public static final int BY_EXTENSION_ASC = 6;
public static final int BY_EXTENSION_DESC = 7;
@IntDef(value = {
BY_NAME_ASC,
BY_NAME_DESC,
BY_TIME_ASC,
BY_TIME_DESC,
BY_SIZE_ASC,
BY_SIZE_DESC,
BY_EXTENSION_ASC,
BY_EXTENSION_DESC
})
@Retention(RetentionPolicy.SOURCE)
public @interface SortType {
}
/**
* 将目录分隔符统一为平台默认的分隔符,并为目录结尾添加分隔符
*/
public static String separator(String path) {
String separator = File.separator;
path = path.replace("\\", separator);
if (!path.endsWith(separator)) {
path += separator;
}
return path;
}
public static void closeSilently(Closeable c) {
if (c == null) {
return;
}
try {
c.close();
} catch (IOException e) {
// do nothing
LogUtils.warn(e);
}
}
/**
* 列出指定目录下的所有子目录
*/
public static File[] listDirs(String startDirPath, String[] excludeDirs, @SortType int sortType) {
LogUtils.verbose(String.format("list dir %s", startDirPath));
ArrayList<File> dirList = new ArrayList<File>();
File startDir = new File(startDirPath);
if (!startDir.isDirectory()) {
return new File[0];
}
File[] dirs = startDir.listFiles(new FileFilter() {
public boolean accept(File f) {
if (f == null) {
return false;
}
//noinspection RedundantIfStatement
if (f.isDirectory()) {
return true;
}
return false;
}
});
if (dirs == null) {
return new File[0];
}
if (excludeDirs == null) {
excludeDirs = new String[0];
}
for (File dir : dirs) {
File file = dir.getAbsoluteFile();
if (!ConvertUtils.toString(excludeDirs).contains(file.getName())) {
dirList.add(file);
}
}
if (sortType == BY_NAME_ASC) {
Collections.sort(dirList, new SortByName());
} else if (sortType == BY_NAME_DESC) {
Collections.sort(dirList, new SortByName());
Collections.reverse(dirList);
} else if (sortType == BY_TIME_ASC) {
Collections.sort(dirList, new SortByTime());
} else if (sortType == BY_TIME_DESC) {
Collections.sort(dirList, new SortByTime());
Collections.reverse(dirList);
} else if (sortType == BY_SIZE_ASC) {
Collections.sort(dirList, new SortBySize());
} else if (sortType == BY_SIZE_DESC) {
Collections.sort(dirList, new SortBySize());
Collections.reverse(dirList);
} else if (sortType == BY_EXTENSION_ASC) {
Collections.sort(dirList, new SortByExtension());
} else if (sortType == BY_EXTENSION_DESC) {
Collections.sort(dirList, new SortByExtension());
Collections.reverse(dirList);
}
return dirList.toArray(new File[dirList.size()]);
}
/**
* 列出指定目录下的所有子目录
*/
public static File[] listDirs(String startDirPath, String[] excludeDirs) {
return listDirs(startDirPath, excludeDirs, BY_NAME_ASC);
}
/**
* 列出指定目录下的所有子目录
*/
public static File[] listDirs(String startDirPath) {
return listDirs(startDirPath, null, BY_NAME_ASC);
}
/**
* 列出指定目录下的所有子目录及所有文件
*/
public static File[] listDirsAndFiles(String startDirPath, String[] allowExtensions) {
File[] dirs, files, dirsAndFiles;
dirs = listDirs(startDirPath);
if (allowExtensions == null) {
files = listFiles(startDirPath);
} else {
files = listFiles(startDirPath, allowExtensions);
}
if (dirs == null || files == null) {
return null;
}
dirsAndFiles = new File[dirs.length + files.length];
System.arraycopy(dirs, 0, dirsAndFiles, 0, dirs.length);
System.arraycopy(files, 0, dirsAndFiles, dirs.length, files.length);
return dirsAndFiles;
}
/**
* 列出指定目录下的所有子目录及所有文件
*/
public static File[] listDirsAndFiles(String startDirPath) {
return listDirsAndFiles(startDirPath, null);
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath, final Pattern filterPattern, @SortType int sortType) {
LogUtils.verbose(String.format("list file %s", startDirPath));
ArrayList<File> fileList = new ArrayList<File>();
File f = new File(startDirPath);
if (!f.isDirectory()) {
return new File[0];
}
File[] files = f.listFiles(new FileFilter() {
public boolean accept(File f) {
if (f == null) {
return false;
}
if (f.isDirectory()) {
return false;
}
//noinspection SimplifiableIfStatement
if (filterPattern == null) {
return true;
}
return filterPattern.matcher(f.getName()).find();
}
});
if (files == null) {
return new File[0];
}
for (File file : files) {
fileList.add(file.getAbsoluteFile());
}
if (sortType == BY_NAME_ASC) {
Collections.sort(fileList, new SortByName());
} else if (sortType == BY_NAME_DESC) {
Collections.sort(fileList, new SortByName());
Collections.reverse(fileList);
} else if (sortType == BY_TIME_ASC) {
Collections.sort(fileList, new SortByTime());
} else if (sortType == BY_TIME_DESC) {
Collections.sort(fileList, new SortByTime());
Collections.reverse(fileList);
} else if (sortType == BY_SIZE_ASC) {
Collections.sort(fileList, new SortBySize());
} else if (sortType == BY_SIZE_DESC) {
Collections.sort(fileList, new SortBySize());
Collections.reverse(fileList);
} else if (sortType == BY_EXTENSION_ASC) {
Collections.sort(fileList, new SortByExtension());
} else if (sortType == BY_EXTENSION_DESC) {
Collections.sort(fileList, new SortByExtension());
Collections.reverse(fileList);
}
return fileList.toArray(new File[fileList.size()]);
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath, Pattern filterPattern) {
return listFiles(startDirPath, filterPattern, BY_NAME_ASC);
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath) {
return listFiles(startDirPath, null, BY_NAME_ASC);
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath, final String[] allowExtensions) {
LogUtils.verbose(String.format("list file %s", startDirPath));
File file = new File(startDirPath);
return file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
//返回当前目录所有以某些扩展名结尾的文件
String extension = FileUtils.getExtension(name);
return ConvertUtils.toString(allowExtensions).contains(extension);
}
});
}
/**
* 列出指定目录下的所有文件
*/
public static File[] listFiles(String startDirPath, String allowExtension) {
return listFiles(startDirPath, new String[]{allowExtension});
}
/**
* 判断文件或目录是否存在
*/
public static boolean exist(String path) {
File file = new File(path);
return file.exists();
}
/**
* 删除文件或目录
*/
public static boolean delete(File file, boolean deleteRootDir) {
LogUtils.verbose(String.format("delete file %s", file.getAbsolutePath()));
boolean result = false;
if (file.isFile()) {
//是文件
result = deleteResolveEBUSY(file);
} else {
//是目录
File[] files = file.listFiles();
if (files == null) {
return false;
}
if (files.length == 0) {
result = deleteRootDir && deleteResolveEBUSY(file);
} else {
for (File f : files) {
delete(f, deleteRootDir);
result = deleteResolveEBUSY(f);
}
}
if (deleteRootDir) {
result = deleteResolveEBUSY(file);
}
}
return result;
}
/**
* bug: open failed: EBUSY (Device or resource busy)
* fix: http://stackoverflow.com/questions/11539657/open-failed-ebusy-device-or-resource-busy
*/
private static boolean deleteResolveEBUSY(File file) {
// Before you delete a Directory or File: rename it!
final File to = new File(file.getAbsolutePath() + System.currentTimeMillis());
//noinspection ResultOfMethodCallIgnored
file.renameTo(to);
return to.delete();
}
/**
* 删除文件或目录
*/
public static boolean delete(String path, boolean deleteRootDir) {
File file = new File(path);
//noinspection SimplifiableIfStatement
if (file.exists()) {
return delete(file, deleteRootDir);
}
return false;
}
/**
* 删除文件或目录, 不删除最顶层目录
*/
public static boolean delete(String path) {
return delete(path, false);
}
/**
* 删除文件或目录, 不删除最顶层目录
*/
public static boolean delete(File file) {
return delete(file, false);
}
/**
* 复制文件为另一个文件,或复制某目录下的所有文件及目录到另一个目录下
*/
public static boolean copy(String src, String tar) {
File srcFile = new File(src);
return srcFile.exists() && copy(srcFile, new File(tar));
}
/**
* 复制文件或目录
*/
public static boolean copy(File src, File tar) {
try {
LogUtils.verbose(String.format("copy %s to %s", src.getAbsolutePath(), tar.getAbsolutePath()));
if (src.isFile()) {
InputStream is = new FileInputStream(src);
OutputStream op = new FileOutputStream(tar);
BufferedInputStream bis = new BufferedInputStream(is);
BufferedOutputStream bos = new BufferedOutputStream(op);
byte[] bt = new byte[1024 * 8];
while (true) {
int len = bis.read(bt);
if (len == -1) {
break;
} else {
bos.write(bt, 0, len);
}
}
bis.close();
bos.close();
} else if (src.isDirectory()) {
File[] files = src.listFiles();
//noinspection ResultOfMethodCallIgnored
tar.mkdirs();
for (File file : files) {
copy(file.getAbsoluteFile(), new File(tar.getAbsoluteFile(), file.getName()));
}
}
return true;
} catch (Exception e) {
LogUtils.error(e);
return false;
}
}
/**
* 移动文件或目录
*/
public static boolean move(String src, String tar) {
return move(new File(src), new File(tar));
}
/**
* 移动文件或目录
*/
public static boolean move(File src, File tar) {
return rename(src, tar);
}
/**
* 文件重命名
*/
public static boolean rename(String oldPath, String newPath) {
return rename(new File(oldPath), new File(newPath));
}
/**
* 文件重命名
*/
public static boolean rename(File src, File tar) {
LogUtils.verbose(String.format("rename %s to %s", src.getAbsolutePath(), tar.getAbsolutePath()));
return src.renameTo(tar);
}
/**
* 读取文本文件, 失败将返回空串
*/
public static String readText(String filepath, String charset) {
LogUtils.verbose(String.format("read %s use %s", filepath, charset));
try {
byte[] data = readBytes(filepath);
if (data != null) {
return new String(data, charset).trim();
}
} catch (UnsupportedEncodingException e) {
LogUtils.warn(e);
}
return "";
}
/**
* 读取文本文件, 失败将返回空串
*/
public static String readText(String filepath) {
return readText(filepath, "utf-8");
}
/**
* 读取文件内容, 失败将返回空串
*/
public static byte[] readBytes(String filepath) {
LogUtils.verbose(String.format("read %s", filepath));
FileInputStream fis = null;
try {
fis = new FileInputStream(filepath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (true) {
int len = fis.read(buffer, 0, buffer.length);
if (len == -1) {
break;
} else {
baos.write(buffer, 0, len);
}
}
byte[] data = baos.toByteArray();
baos.close();
return data;
} catch (IOException e) {
LogUtils.warn(e);
return null;
} finally {
closeSilently(fis);
}
}
/**
* 保存文本内容
*/
public static boolean writeText(String filepath, String content, String charset) {
try {
writeBytes(filepath, content.getBytes(charset));
return true;
} catch (UnsupportedEncodingException e) {
LogUtils.warn(e);
return false;
}
}
/**
* 保存文本内容
*/
public static boolean writeText(String filepath, String content) {
return writeText(filepath, content, "utf-8");
}
/**
* 保存文件内容
*/
public static boolean writeBytes(String filepath, byte[] data) {
LogUtils.verbose(String.format("write %s", filepath));
File file = new File(filepath);
FileOutputStream fos = null;
try {
if (!file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.getParentFile().mkdirs();
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
}
fos = new FileOutputStream(filepath);
fos.write(data);
return true;
} catch (IOException e) {
LogUtils.warn(e);
return false;
} finally {
closeSilently(fos);
}
}
/**
* 追加文本内容
*/
public static boolean appendText(String path, String content) {
LogUtils.verbose(String.format("append %s", path));
File file = new File(path);
FileWriter writer = null;
try {
if (!file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
}
writer = new FileWriter(file, true);
writer.write(content);
return true;
} catch (IOException e) {
LogUtils.warn(e);
return false;
} finally {
closeSilently(writer);
}
}
/**
* 获取文件大小
*/
public static long getLength(String path) {
File file = new File(path);
if (!file.isFile() || !file.exists()) {
return 0;
}
return file.length();
}
/**
* 获取文件或网址的名称(包括后缀)
*/
public static String getName(String pathOrUrl) {
if (pathOrUrl == null) {
return "";
}
int pos = pathOrUrl.lastIndexOf('/');
if (0 <= pos) {
return pathOrUrl.substring(pos + 1);
} else {
return String.valueOf(System.currentTimeMillis()) + "." + getExtension(pathOrUrl);
}
}
/**
* 获取文件名(不包括扩展名)
*/
public static String getNameExcludeExtension(String path) {
try {
String fileName = (new File(path)).getName();
int lastIndexOf = fileName.lastIndexOf(".");
if (lastIndexOf != -1) {
fileName = fileName.substring(0, lastIndexOf);
}
return fileName;
} catch (Exception e) {
LogUtils.warn(e);
return "";
}
}
/**
* 获取格式化后的文件大小
*/
public static String getSize(String path) {
long fileSize = getLength(path);
return ConvertUtils.toFileSizeString(fileSize);
}
/**
* 获取文件后缀,不包括“.”
*/
public static String getExtension(String pathOrUrl) {
int dotPos = pathOrUrl.lastIndexOf('.');
if (0 <= dotPos) {
return pathOrUrl.substring(dotPos + 1);
} else {
return "ext";
}
}
/**
* 获取文件的MIME类型
*/
public static String getMimeType(String pathOrUrl) {
String ext = getExtension(pathOrUrl);
MimeTypeMap map = MimeTypeMap.getSingleton();
String mimeType;
if (map.hasExtension(ext)) {
mimeType = map.getMimeTypeFromExtension(ext);
} else {
mimeType = "*/*";
}
LogUtils.verbose(pathOrUrl + ": " + mimeType);
return mimeType;
}
/**
* 获取格式化后的文件/目录创建或最后修改时间
*/
public static String getDateTime(String path) {
return getDateTime(path, "yyyy年MM月dd日HH:mm");
}
/**
* 获取格式化后的文件/目录创建或最后修改时间
*/
public static String getDateTime(String path, String format) {
File file = new File(path);
return getDateTime(file, format);
}
/**
* 获取格式化后的文件/目录创建或最后修改时间
*/
public static String getDateTime(File file, String format) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(file.lastModified());
return DateUtils.formatDate(cal.getTime(), format);
}
/**
* 比较两个文件的最后修改时间
*/
public static int compareLastModified(String path1, String path2) {
long stamp1 = (new File(path1)).lastModified();
long stamp2 = (new File(path2)).lastModified();
if (stamp1 > stamp2) {
return 1;
} else if (stamp1 < stamp2) {
return -1;
} else {
return 0;
}
}
/**
* 创建多级别的目录
*/
public static boolean makeDirs(String path) {
return makeDirs(new File(path));
}
/**
* 创建多级别的目录
*/
public static boolean makeDirs(File file) {
return file.mkdirs();
}
public static class SortByExtension implements Comparator<File> {
public SortByExtension() {
super();
}
public int compare(File f1, File f2) {
if (f1 == null || f2 == null) {
if (f1 == null) {
return -1;
} else {
return 1;
}
} else {
if (f1.isDirectory() && f2.isFile()) {
return -1;
} else if (f1.isFile() && f2.isDirectory()) {
return 1;
} else {
return f1.getName().compareToIgnoreCase(f2.getName());
}
}
}
}
public static class SortByName implements Comparator<File> {
private boolean caseSensitive;
public SortByName(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
public SortByName() {
this.caseSensitive = false;
}
public int compare(File f1, File f2) {
if (f1 == null || f2 == null) {
if (f1 == null) {
return -1;
} else {
return 1;
}
} else {
if (f1.isDirectory() && f2.isFile()) {
return -1;
} else if (f1.isFile() && f2.isDirectory()) {
return 1;
} else {
String s1 = f1.getName();
String s2 = f2.getName();
if (caseSensitive) {
return s1.compareTo(s2);
} else {
return s1.compareToIgnoreCase(s2);
}
}
}
}
}
public static class SortBySize implements Comparator<File> {
public SortBySize() {
super();
}
public int compare(File f1, File f2) {
if (f1 == null || f2 == null) {
if (f1 == null) {
return -1;
} else {
return 1;
}
} else {
if (f1.isDirectory() && f2.isFile()) {
return -1;
} else if (f1.isFile() && f2.isDirectory()) {
return 1;
} else {
if (f1.length() < f2.length()) {
return -1;
} else {
return 1;
}
}
}
}
}
public static class SortByTime implements Comparator<File> {
public SortByTime() {
super();
}
public int compare(File f1, File f2) {
if (f1 == null || f2 == null) {
if (f1 == null) {
return -1;
} else {
return 1;
}
} else {
if (f1.isDirectory() && f2.isFile()) {
return -1;
} else if (f1.isFile() && f2.isDirectory()) {
return 1;
} else {
if (f1.lastModified() > f2.lastModified()) {
return -1;
} else {
return 1;
}
}
}
}
}
}