/*
Copyright 2012-2013, Polyvi Inc. (http://polyvi.github.io/openxface)
This program is distributed under the terms of the GNU General Public License.
This file is part of xFace.
xFace is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
xFace 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with xFace. If not, see <http://www.gnu.org/licenses/>.
*/
package com.polyvi.xface.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Date;
import android.content.Context;
import android.content.res.Resources.NotFoundException;
import android.os.Environment;
import android.webkit.MimeTypeMap;
import com.polyvi.xface.core.XConfiguration;
import com.polyvi.xface.core.XISystemContext;
public class XFileUtils {
private final static String CLASS_NAME = XFileUtils.class.getSimpleName();
// TODO:只加需要的权限,不覆盖已有权限
public final static String ALL_PERMISSION = "777"; // 文件权限:全部权限
public final static String EXECUTABLE_BY_OTHER = "701"; // 文件权限:其他用户组可执行
public final static String READABLE_BY_OTHER = "704"; // 文件权限:其他用户组可读
public final static String READABLE_AND_EXECUTEBLE_BY_OTHER = "705";// 文件权限:其他用户可读可执行
private static final int OCTAL_RADIX = 8; // 八进制基数
private static String NO_MEDIA_FILE_NAME = ".nomedia";
/**
* 写文件
*
* @param filePath
* 要写入的文件的路径
* @param data
* 要写入的数据
* @return 开始写入数据的位置
*/
public static long write(String fileName, String data, int position)
throws FileNotFoundException, IOException {
boolean append = false;
if (position > 0) {
truncateFile(fileName, position);
append = true;
}
byte[] rawData = data.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(rawData);
FileOutputStream out = new FileOutputStream(fileName, append);
byte buff[] = new byte[rawData.length];
in.read(buff, 0, buff.length);
out.write(buff, 0, rawData.length);
out.flush();
out.close();
return data.length();
}
/**
* 清除指定长度后的文件内容
*
* @param filePath
* 要清除的文件的路径
* @param size
* 清除size后的文件
* @return 剩下的文件长度
*/
public static long truncateFile(String fileName, long size)
throws FileNotFoundException, IOException {
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
if (raf.length() >= size) {
FileChannel channel = raf.getChannel();
channel.truncate(size);
return size;
}
return raf.length();
}
/**
* 获取指定文件类型
*
* @param fileName
* 文件的路径
* @return 文件的类型
*/
public static String getMimeType(String filename) {
MimeTypeMap map = MimeTypeMap.getSingleton();
return map.getMimeTypeFromExtension(MimeTypeMap
.getFileExtensionFromUrl(filename));
}
/**
* 创建文件和文件所在的目录
*
* @param path
* 文件的绝对路径
* @return 成功返回true,失败返回false
*/
public static Boolean createFile(String path) {
File file = new File(path);
File parantFile = file.getParentFile();
if (null != parantFile && !parantFile.exists() && !parantFile.mkdirs()) {
return false;
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 获得当前系统的sdcard路径
*
* @return 如果sdcard可访问,则返回带当前系统的sdcard路径,否则返回null。
*/
public static String getSdcardPath() {
String path = null;
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
path = Environment.getExternalStorageDirectory().getAbsolutePath();
} else {
path = XExternalStorageScanner.getExternalStoragePath();
}
if (null == path) {
XLog.w(CLASS_NAME, "No External Storage");
return null;
}
File filePath = null;
try {
filePath = new File(path).getCanonicalFile();
} catch (IOException e) {
XLog.e(CLASS_NAME, e.getMessage());
e.printStackTrace();
return null;
}
return filePath.getAbsolutePath();
}
/**
* 修改文件的权限
*
* @param permission
* 权限
* @param path
* 文件路径
*/
public static void setPermission(String permission, String path) {
XNativeBridge.chmod(path, Integer.parseInt(permission, OCTAL_RADIX));
}
/**
* 循环修改目录的权限到dir目录
*
* @param permission
* 文件的权限
* @param filePath
* 修改文件权限的文件路径
* @param dir
* 修改文件权限的限制位置(当需要修改到filePath的根目录的时候这个传"/"即可)
*/
public static void setPermissionUntilDir(String permission,
String filePath, String dir) {
String dirPath = new File(dir).getAbsolutePath();
if (null == filePath || !filePath.startsWith(dirPath)) {
return;
}
File fileObj = new File(filePath);
while (!dirPath.equals(fileObj.getAbsolutePath())) {
String path = fileObj.getAbsolutePath();
// 设置文件权限
setPermission(permission, path);
fileObj = new File(fileObj.getParent());
}
}
/**
* 检查给定的文件路径是否存在
*
* @param filePath
* 给定的文件路径
* @return true:存在,false:不存在.
*/
public static boolean checkFileExist(String filePath) {
if (XStringUtils.isEmptyString(filePath)) {
XLog.e(CLASS_NAME, "filePath is empty");
return false;
}
if (!new File(filePath).exists()) {
XLog.e(CLASS_NAME, filePath + " not exist");
return false;
}
return true;
}
/**
* 创建临时目录 返回临时目录所创建的目录
*
* @param parent
* 临时目录所在的父目录 parent必须要存在
* @return 创建失败 返回null 否则返回目录名
*/
public static String createTempDir(String parent) {
if (!parent.endsWith("/")) {
parent += "/";
}
String dirPath = parent + String.valueOf(new Date().getSeconds())
+ XUtils.generateRandomId() + "tmp";
File tmpFile = new File(dirPath);
return tmpFile.mkdir() ? tmpFile.getAbsolutePath() : null;
}
/**
* 拷贝文件或者目录
*
* @param src
* 待拷贝的源文件或者目录
* @param des
* 拷贝的目的目录
* @throws IOException
*/
public static void copy(File srcLocation, File desLocation)
throws IOException {
if (srcLocation.isDirectory()) {
if (!desLocation.exists() && !desLocation.mkdirs()) {
throw new IOException("can't create dir "
+ desLocation.getAbsolutePath());
}
String[] children = srcLocation.list();
for (int i = 0; i < children.length; i++) {
copy(new File(srcLocation, children[i]), new File(desLocation,
children[i]));
}
} else {
File direcory = desLocation.getParentFile();
if (direcory != null && !direcory.exists() && !direcory.mkdirs()) {
throw new IOException("can't create dir "
+ direcory.getAbsolutePath());
}
InputStream in = new FileInputStream(srcLocation);
OutputStream out = new FileOutputStream(desLocation);
byte[] buf = new byte[XConstant.BUFFER_LEN];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
/**
* 递归的遍历目录
*
* @param srcDir
* 需要遍历的目录路径
* @param handler
* 文件处理器
*/
public static void walkDirectory(String srcDir, XFileVisitor visitor) {
walkDirectory(new File(srcDir), visitor);
}
/**
* 递归的遍历目录
*
* @param srcDir
* 需要遍历的目录对象
* @param visitor
* 文件处理器
*/
public static void walkDirectory(File srcDir, XFileVisitor visitor) {
if (!srcDir.exists() || !srcDir.isDirectory()
|| !visitor.isContinueTraverse()) {
return;
}
File files[] = srcDir.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
visitor.visit(files[i].getAbsolutePath());
} else {
walkDirectory(files[i], visitor);
}
}
}
/**
* 获取url的MIMEType类型
*
* @paramm url url地址
* @return MIMEType类型
*/
public static String getMIMEType(String url) {
int dotIndex = url.lastIndexOf(".");
/* 获取文件的后缀名 */
return dotIndex < 0 ? "*/*"
: MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(
url.substring(dotIndex + 1, url.length())
.toLowerCase());
}
/**
* 删除给定路径的目录或文件,如果给定路径是一个目录,则递归删除目录
*
* @param path
* 目录/文件路径
*/
public static boolean deleteFileRecursively(String path) {
File destFile = new File(path);
if (!destFile.exists()) {
return true;
}
if (destFile.isFile()) {
destFile.delete();
return true;
}
String[] childNames = destFile.list();
for (String child : childNames) {
if (!deleteFileRecursively(new File(path, child).getAbsolutePath())) {
return false;
}
}
return destFile.delete();
}
/**
* 创建一个文件并写入文件内容<br>
* 如果文件存在,则会被覆写;如果该文件所在目录不存在,会自动被创建
*
* @param filePath
* 新建文件的绝对路径
* @param is
* 存放写入文件数据的输入流对象
*/
public static void createFileByData(String filePath, InputStream is) {
try {
File destFile = new File(filePath);
File parentFile = destFile.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
FileOutputStream fos = new FileOutputStream(destFile);
byte[] buffer = new byte[XConstant.BUFFER_LEN];
int len = 0;
while (-1 != (len = is.read(buffer))) {
fos.write(buffer, 0, len);
}
fos.close();
} catch (IOException e) {
XLog.e(CLASS_NAME, e.getMessage());
e.printStackTrace();
}
}
/**
* 解压zip文件
*
* @param targetPath
* 解压的目标路径
* @param zipFilePath
* zip包路径
* @return 是否成功
*/
public static boolean unzipFile(String targetPath, String zipFilePath) {
try {
XZipper zipper = new XZipper();
zipper.unzipFile(targetPath, zipFilePath);
return true;
} catch (FileNotFoundException e) {
XLog.e(CLASS_NAME, "The zip file: " + zipFilePath
+ "does not exist!");
e.printStackTrace();
return false;
} catch (IOException e) {
XLog.e(CLASS_NAME, "Unzip file: " + zipFilePath + " failed!");
e.printStackTrace();
return false;
}
}
/**
* 从assets文件资源中读取zip包进行解压
*
* @param targetPath
* 解压的目标目录路径
* @param context
* @param assetFileName
* 要解压的assets资源文件名
*/
public static boolean unzipFileFromAsset(String targetPath,
Context context, String assetFileName) {
try {
return new XZipper().unzipFileFromAsset(targetPath, context,
assetFileName);
} catch (IOException e) {
XLog.e(CLASS_NAME, "Unzip file failed: Can't find assets file: "
+ assetFileName);
return false;
}
}
/**
* 读取文件中的数据
*
* @param filePath
* 文件绝对路径
* @return 字符串形式的文件数据
*/
public static String readFileContent(String filePath) {
if (null == filePath) {
return null;
}
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(filePath);
byte[] buffer = new byte[XConstant.BUFFER_LEN];
int len = 0;
while ((len = fis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
String content = bos.toString();
bos.close();
fis.close();
return content;
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 判断文件路径是否有效,或者含有特殊字符
*
* @param filePath
* @return
*/
public static boolean isFilePathValid(String filePath) {
if (XStringUtils.isEmptyString(filePath)) {
XLog.e(CLASS_NAME, "This path is illegal.");
return false;
} else if (filePath.contains(":")) {
// Check for a ":" character in the file to line up with BB and iOS
XLog.e(CLASS_NAME, "This path has an invalid \":\" in it.");
return false;
}
return true;
}
/**
* 判断指定文件是否在另一个文件夹中 当childPath和parentPath相同时也表示childPath在parentPath中
*
* @param parentPath
* 父文件夹路径
* @param childPath
* 指定的文件路径
* @return true:表示在parentPath中,false:表示不在parentPath中
*/
public static boolean isFileAncestorOf(String parentPath, String childPath) {
if (!parentPath.endsWith(File.separator)) {
parentPath += File.separator;
}
if (!childPath.endsWith(File.separator)) {
childPath += File.separator;
}
return childPath.startsWith(parentPath);
}
/**
* 拷贝xface.js, plugin, cordova_plugins.js到新安装应用所在目录
*
* @param context
* android程序运行时上下文
* @param targetDir
* 拷贝xface.js, plugin, cordova_plugins.js的目的目录(绝对路径)
*/
public static void copyEmbeddedJsFile(XISystemContext systemContext,
String startAppDir, String targetDir) {
try {
String jsFileparentPath = startAppDir + File.separator;
if (jsFileparentPath.contains(XConstant.ASSERT_PROTACAL)) {
copyJsFromAssets(systemContext, targetDir, jsFileparentPath);
} else {
copyJsFromSdcard(targetDir, jsFileparentPath);
}
} catch (NotFoundException e) {
XLog.e(CLASS_NAME, "copyEmbeddedJsFile error!");
e.printStackTrace();
} catch (IOException e) {
XLog.e(CLASS_NAME, "copyEmbeddedJsFile error!");
e.printStackTrace();
}
}
/**
* 从assets下进行拷贝js文件
*
* @param systemContext
* @param targetDir
* 目标路径
* @param jsFileparentPath
* js文件的父目录
*/
public static void copyJsFromAssets(XISystemContext systemContext,
String targetDir, String jsFileparentPath) {
jsFileparentPath = jsFileparentPath.substring(XConstant.ASSERT_PROTACAL
.length());
Context context = systemContext.getContext();
// 1.copy xface.js
File desjsFile = new File(targetDir, XConstant.XFACE_JS_FILE_NAME);
boolean ret = XAssetsFileUtils.copyAssetsToTarget(context,
jsFileparentPath + XConstant.XFACE_JS_FILE_NAME,
desjsFile.getAbsolutePath());
if (!ret) {
throw new NotFoundException();
}
// 2.copy cordova_plugins.js
desjsFile = new File(targetDir, XConstant.PLUGIN_JS_METADATA_FILE);
String pluginJs = jsFileparentPath + XConstant.PLUGIN_JS_METADATA_FILE;
if (XAssetsFileUtils.checkIfInAssets(context, pluginJs)) {
ret = XAssetsFileUtils.copyAssetsToTarget(context, pluginJs,
desjsFile.getAbsolutePath());
if (!ret) {
throw new NotFoundException();
}
}
// 3.copy plugin js dir
String pluginDir = jsFileparentPath + "plugins";
if (XAssetsFileUtils.checkIfInAssets(context, pluginDir)) {
ret = XAssetsFileUtils.copyAssetsToTarget(context, pluginDir,
targetDir + "/" + "plugins");
if (!ret) {
throw new NotFoundException();
}
}
}
/**
* 从sdcard下进行拷贝js文件
*
* @param targetDir
* 目标路径
* @param jsFileparentPath
* js文件的父目录
*/
private static void copyJsFromSdcard(String targetDir,
String jsFileparentPath) throws IOException {
jsFileparentPath = jsFileparentPath.substring(XConstant.FILE_SCHEME
.length());
// 1.copy xface.js
File srcJsFile = new File(jsFileparentPath,
XConstant.XFACE_JS_FILE_NAME);
File desJsFile = new File(targetDir, XConstant.XFACE_JS_FILE_NAME);
copy(srcJsFile, desJsFile);
// 2.copy cordova_plugins.js
srcJsFile = new File(jsFileparentPath,
XConstant.PLUGIN_JS_METADATA_FILE);
desJsFile = new File(targetDir, XConstant.PLUGIN_JS_METADATA_FILE);
if (srcJsFile.exists()) {
// maybe not exist when singfile xface.js
copy(srcJsFile, desJsFile);
}
// 3.copy plugin js dir
srcJsFile = new File(jsFileparentPath, "plugins");
desJsFile = new File(targetDir + "/" + "plugins");
if (srcJsFile.exists()) {
// maybe not exist when singfile xface.js
copy(srcJsFile, desJsFile);
}
}
/**
* 在xFace的wordDir下创建.nomedia文件
*/
public static void createNoMediaFileInWorkDir() {
File file = new File(XConfiguration.getInstance().getWorkDirectory(),
NO_MEDIA_FILE_NAME);
try {
if (!file.exists()) {
file.createNewFile();
}
} catch (IOException e) {
XLog.e(CLASS_NAME, "create .nomedia in workDir failed.");
}
}
/**
* 以字符方式写文件
*
* @param filePath
* 文件的绝对路径
* @param fileContent
* 要写的内容
* @return 成功返回true,失败返回false
*/
public static Boolean writeFileByByte(String filePath, byte[] fileContent) {
try {
if (null == filePath || null == fileContent) {
return false;
}
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
fileOutputStream.write(fileContent);
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
XLog.d(CLASS_NAME, e.getMessage());
return false;
}
return true;
}
/**
* 以字符串的方式写文件
*
* @param filePath
* 文件的绝对路径
* @param fileContent
* 要写的文件内容
* @return 成功返回true,失败返回false
*/
public static boolean writeFileByString(String filePath, String fileContent) {
if (null == filePath || null == fileContent) {
return false;
}
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
new FileOutputStream(filePath));
outputStreamWriter.write(fileContent, 0, fileContent.length());
outputStreamWriter.flush();
outputStreamWriter.close();
} catch (IOException e) {
e.printStackTrace();
XLog.d(CLASS_NAME, e.getMessage());
return false;
}
return true;
}
/**
* 以字节流的方式读文件
*
* @param filePath
* 文件的绝对路径
* @return 成功则返回文件内容的字节流,否则为null
*/
public static byte[] readBytesFromFile(String filePath) {
if (null == filePath) {
return null;
}
InputStream is = null;
try {
is = new FileInputStream(filePath);
return XUtils.readBytesFromInputStream(is);
} catch (Exception e) {
XLog.d(CLASS_NAME, "readFileByByte:" + e.getMessage());
e.printStackTrace();
return null;
}
}
/**
* 判断文件是否存在
*
* @param filePath
* [in] 文件路径
* @return
*/
public static boolean fileExists(Context context, String filePath) {
if (null == filePath) {
return false;
}
String absPath = null;
if (filePath.startsWith(XConstant.ASSERT_PROTACAL)) {
absPath = filePath.substring(XConstant.ASSERT_PROTACAL.length());
try {
InputStream is = context.getAssets().open(absPath);
if (is != null) {
return true;
}
} catch (IOException e) {
return false;
}
} else if (filePath.startsWith(XConstant.FILE_SCHEME)) {
File file = new File(filePath.substring(XConstant.FILE_SCHEME
.length()));
if (file.exists()) {
return true;
}
}
return false;
}
}