小米開原始檔管理器MiCodeFileExplorer-原始碼研究(3)-使用最多的工具類Util
Util.java,使用最廣泛~
程式碼中很多地方,都寫了註釋說明~基本不需要怎麼解釋了~
遇到一個奇怪的問題,為了驗證某個函式,寫了個main函式執行,結果發生了奇葩事項~
在Java環境下的工程中執行以下程式碼,正常輸出。
列印“C:/a/b/c”
在Android環境下的工程中,竟然直接把JVM搞崩潰了,不明所以啊~
Invalid layout of java.lang.String at value
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (javaClasses.cpp:129), pid=8236, tid=3188
# fatal error: Invalid layout of preloaded class
#
# JRE version: 7.0_17-b02
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.7-b01 mixed mode windows-amd64 compressed oops)
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# J:\AndroidCenter\MiCodeFileExplorer\hs_err_pid8236.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.sun.com/bugreport/crash.jsp
#
程式碼中很多地方,都寫了註釋說明~基本不需要怎麼解釋了~
package net.micode.fileexplorer.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import net.micode.fileexplorer.FileViewActivity;
import net.micode.fileexplorer.GlobalConsts;
import net.micode.fileexplorer.R;
import net.micode.fileexplorer.model.FavoriteItem;
import net.micode.fileexplorer.model.FileInfo;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.util.Log;
import android.view.ActionMode;
import android.view.View;
import android.widget.TextView;
/**工具類,包含了很多通用的工具方法,被專案中的很多類呼叫。*/
public class Util {
//這個資料夾裡面儲存的內容是app2sd產生的資料夾,也就是是你手機上所有安裝到SD卡的應用程式的快取資料夾。
//androidsecure資料夾可以刪除嗎?
//如果刪除之後,軟體不能正常使用,和系統沒有關係。
//刪的話除了會可能導致移動至sd卡的程式損壞,資料丟失,並不會造成什麼嚴重後果。只要把移動到sd卡的損壞程式解除安裝,重灌,手機就完全沒有損傷,資料夾也會在再次app2sd時自動重建的。
private static String ANDROID_SECURE = "/mnt/sdcard/.android_secure";
//android.util.Log.log第1個引數,用到“tag”,和log4j中Logger.getLogger(getClass())用法不太一樣
private static final String LOG_TAG = "Util";
//獲得SD卡的儲存狀態,“mounted”表示已經就緒
public static boolean isSDCardReady() {
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}
// if path1 contains path2
public static boolean containsPath(String path1, String path2) {
String path = path2;
while (path != null) {
if (path.equalsIgnoreCase(path1))
return true;
if (path.equals(GlobalConsts.ROOT_PATH))
break;
path = new File(path).getParent();
}
return false;
}
//2個路徑相加的時候,是否需要加上檔案分隔符
public static String makePath(String path1, String path2) {
if (path1.endsWith(File.separator))
return path1 + path2;
return path1 + File.separator + path2;
}
//獲得SD卡的儲存目錄
public static String getSdDirectory() {
return Environment.getExternalStorageDirectory().getPath();
}
//判斷1個檔案是否為“普通檔案”,ANDROID_SECURE下的檔案都不是普通的
public static boolean isNormalFile(String fullName) {
return !fullName.equals(ANDROID_SECURE);
}
//根據檔案路徑,獲得Java檔案File,再包裝成FileInfo
public static FileInfo GetFileInfo(String filePath) {
File lFile = new File(filePath);
if (!lFile.exists())
return null;
FileInfo lFileInfo = new FileInfo();
lFileInfo.canRead = lFile.canRead();
lFileInfo.canWrite = lFile.canWrite();
lFileInfo.isHidden = lFile.isHidden();
lFileInfo.fileName = Util.getNameFromFilepath(filePath);
lFileInfo.ModifiedDate = lFile.lastModified();
lFileInfo.IsDir = lFile.isDirectory();
lFileInfo.filePath = filePath;
lFileInfo.fileSize = lFile.length();
return lFileInfo;
}
//根據File物件,和FilenameFilter等選項,獲得包裝的FileInfo
//需要注意多少,如果File是個目錄,Count就是當前目錄下的檔案的個數。如果是普通檔案,就計算檔案大小。
//這個時候,我們知道Count欄位的含義了
public static FileInfo GetFileInfo(File f, FilenameFilter filter,
boolean showHidden) {
FileInfo lFileInfo = new FileInfo();
String filePath = f.getPath();
File lFile = new File(filePath);
lFileInfo.canRead = lFile.canRead();
lFileInfo.canWrite = lFile.canWrite();
lFileInfo.isHidden = lFile.isHidden();
lFileInfo.fileName = f.getName();
lFileInfo.ModifiedDate = lFile.lastModified();
lFileInfo.IsDir = lFile.isDirectory();
lFileInfo.filePath = filePath;
if (lFileInfo.IsDir) {
int lCount = 0;
File[] files = lFile.listFiles(filter);
// null means we cannot access this dir
if (files == null) {
return null;
}
for (File child : files) {
if ((!child.isHidden() || showHidden)
&& Util.isNormalFile(child.getAbsolutePath())) {
lCount++;
}
}
lFileInfo.Count = lCount;
} else {
lFileInfo.fileSize = lFile.length();
}
return lFileInfo;
}
/*
* 採用了新的辦法獲取APK圖示,之前的失敗是因為android中存在的一個BUG,通過 appInfo.publicSourceDir =
* apkPath;來修正這個問題,詳情參見:
* http://code.google.com/p/android/issues/detail?id=9151
*/
public static Drawable getApkIcon(Context context, String apkPath) {
//Android系統為我們提供了很多服務管理類,包括ActivityManager、PowerManager(電源管理)、AudioManager(音訊管理)。
//PackageManager主要是管理應用程式包,通過它就可以獲取應用程式資訊
PackageManager pm = context.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(apkPath,
PackageManager.GET_ACTIVITIES);
if (info != null) {
ApplicationInfo appInfo = info.applicationInfo;
appInfo.sourceDir = apkPath;
appInfo.publicSourceDir = apkPath;
try {
return appInfo.loadIcon(pm);
} catch (OutOfMemoryError e) {
Log.e(LOG_TAG, e.toString());
}
}
return null;
}
//獲得檔案的副檔名
public static String getExtFromFilename(String filename) {
int dotPosition = filename.lastIndexOf('.');
if (dotPosition != -1) {
return filename.substring(dotPosition + 1, filename.length());
}
return "";
}
//獲得去掉“檔案字尾”的檔名字,比如“C:/a/b/c.png”,輸出“C:/a/b/c”
public static String getNameFromFilename(String filename) {
int dotPosition = filename.lastIndexOf('.');
if (dotPosition != -1) {
return filename.substring(0, dotPosition);
}
return "";
}
//從檔案路徑中,獲得路徑
public static String getPathFromFilepath(String filepath) {
int pos = filepath.lastIndexOf('/');
if (pos != -1) {
return filepath.substring(0, pos);
}
return "";
}
//從檔案路徑中,獲得檔名(帶字尾,如果有)
public static String getNameFromFilepath(String filepath) {
int pos = filepath.lastIndexOf('/');
if (pos != -1) {
return filepath.substring(pos + 1);
}
return "";
}
// return new file path if successful, or return null
public static String copyFile(String src, String dest) {
File file = new File(src);
if (!file.exists() || file.isDirectory()) {
Log.v(LOG_TAG, "copyFile: file not exist or is directory, " + src);
return null;
}
FileInputStream fi = null;
FileOutputStream fo = null;
try {
fi = new FileInputStream(file);
File destPlace = new File(dest);
if (!destPlace.exists()) {
if (!destPlace.mkdirs())
return null;
}
String destPath = Util.makePath(dest, file.getName());
File destFile = new File(destPath);
int i = 1;
while (destFile.exists()) {
String destName = Util.getNameFromFilename(file.getName())
+ " " + i++ + "."
+ Util.getExtFromFilename(file.getName());
destPath = Util.makePath(dest, destName);
destFile = new File(destPath);
}
if (!destFile.createNewFile())
return null;
fo = new FileOutputStream(destFile);
int count = 102400;
byte[] buffer = new byte[count];
int read = 0;
while ((read = fi.read(buffer, 0, count)) != -1) {
fo.write(buffer, 0, read);
}
// TODO: set access privilege
return destPath;
} catch (FileNotFoundException e) {
Log.e(LOG_TAG, "copyFile: file not found, " + src);
e.printStackTrace();
} catch (IOException e) {
Log.e(LOG_TAG, "copyFile: " + e.toString());
} finally {
try {
if (fi != null)
fi.close();
if (fo != null)
fo.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
// does not include sd card folder
private static String[] SysFileDirs = new String[] { "miren_browser/imagecaches" };
//判斷一個檔案是否需要顯示,根據Setting中的設定。特別說明:某個系統檔案目錄,不顯示。
public static boolean shouldShowFile(String path) {
return shouldShowFile(new File(path));
}
//判斷一個檔案是否需要顯示,根據Setting中的設定。特別說明:某個系統檔案目錄,不顯示。
public static boolean shouldShowFile(File file) {
boolean show = Settings.instance().getShowDotAndHiddenFiles();
if (show)
return true;
if (file.isHidden())
return false;
if (file.getName().startsWith("."))
return false;
String sdFolder = getSdDirectory();
for (String s : SysFileDirs) {
if (file.getPath().startsWith(makePath(sdFolder, s)))
return false;
}
return true;
}
//根據上下文物件Context,獲得預設的收藏集合
public static ArrayList<FavoriteItem> getDefaultFavorites(Context context) {
ArrayList<FavoriteItem> list = new ArrayList<FavoriteItem>();
list.add(new FavoriteItem(context.getString(R.string.favorite_photo),
makePath(getSdDirectory(), "DCIM/Camera")));
list.add(new FavoriteItem(context.getString(R.string.favorite_sdcard),
getSdDirectory()));
// list.add(new FavoriteItem(context.getString(R.string.favorite_root),
// getSdDirectory()));
list.add(new FavoriteItem(context
.getString(R.string.favorite_screen_cap), makePath(
getSdDirectory(), "MIUI/screen_cap")));
list.add(new FavoriteItem(
context.getString(R.string.favorite_ringtone), makePath(
getSdDirectory(), "MIUI/ringtone")));
return list;
}
//向View中的某個TextView設定文字
public static boolean setText(View view, int id, String text) {
TextView textView = (TextView) view.findViewById(id);
if (textView == null)
return false;
textView.setText(text);
return true;
}
//向View中的某個TextView設定文字
public static boolean setText(View view, int id, int text) {
TextView textView = (TextView) view.findViewById(id);
if (textView == null)
return false;
textView.setText(text);
return true;
}
// comma separated number
public static String convertNumber(long number) {
return String.format("%,d", number);
}
// storage, G M K B
public static String convertStorage(long size) {
long kb = 1024;
long mb = kb * 1024;
long gb = mb * 1024;
if (size >= gb) {
return String.format("%.1f GB", (float) size / gb);
} else if (size >= mb) {
float f = (float) size / mb;
return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
} else if (size >= kb) {
float f = (float) size / kb;
return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
} else
return String.format("%d B", size);
}
public static class SDCardInfo {
public long total;
public long free;
}
//獲得SD卡的各種資訊,總容量大小和剩餘容量大小等
public static SDCardInfo getSDCardInfo() {
String sDcString = android.os.Environment.getExternalStorageState();
if (sDcString.equals(android.os.Environment.MEDIA_MOUNTED)) {
File pathFile = android.os.Environment
.getExternalStorageDirectory();
try {
android.os.StatFs statfs = new android.os.StatFs(
pathFile.getPath());
// 獲取SDCard上BLOCK總數
long nTotalBlocks = statfs.getBlockCount();
// 獲取SDCard上每個block的SIZE
long nBlocSize = statfs.getBlockSize();
// 獲取可供程式使用的Block的數量
long nAvailaBlock = statfs.getAvailableBlocks();
// 獲取剩下的所有Block的數量(包括預留的一般程式無法使用的塊)
long nFreeBlock = statfs.getFreeBlocks();
SDCardInfo info = new SDCardInfo();
// 計算SDCard 總容量大小MB
info.total = nTotalBlocks * nBlocSize;
// 計算 SDCard 剩餘大小MB
info.free = nAvailaBlock * nBlocSize;
return info;
} catch (IllegalArgumentException e) {
Log.e(LOG_TAG, e.toString());
}
}
return null;
}
//顯示一條系統通知
public static void showNotification(Context context, Intent intent,
String title, String body, int drawableId) {
NotificationManager manager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(drawableId, body,
System.currentTimeMillis());
notification.flags = Notification.FLAG_AUTO_CANCEL;
notification.defaults = Notification.DEFAULT_SOUND;
if (intent == null) {
// FIXEME: category tab is disabled
intent = new Intent(context, FileViewActivity.class);
}
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
intent, PendingIntent.FLAG_ONE_SHOT);
notification.setLatestEventInfo(context, title, body, contentIntent);
manager.notify(drawableId, notification);
}
//格式化毫秒格式的時間
public static String formatDateString(Context context, long time) {
DateFormat dateFormat = android.text.format.DateFormat
.getDateFormat(context);
DateFormat timeFormat = android.text.format.DateFormat
.getTimeFormat(context);
Date date = new Date(time);
return dateFormat.format(date) + " " + timeFormat.format(date);
}
public static void updateActionModeTitle(ActionMode mode, Context context,
int selectedNum) {
if (mode != null) {
mode.setTitle(context.getString(R.string.multi_select_title,
selectedNum));
if (selectedNum == 0) {
mode.finish();
}
}
}
//MimeType
public static HashSet<String> sDocMimeTypesSet = new HashSet<String>() {
{
add("text/plain");
add("text/plain");
add("application/pdf");
add("application/msword");
add("application/vnd.ms-excel");
add("application/vnd.ms-excel");
}
};
public static String sZipFileMimeType = "application/zip";
public static int CATEGORY_TAB_INDEX = 0;
public static int SDCARD_TAB_INDEX = 1;
}
遇到一個奇怪的問題,為了驗證某個函式,寫了個main函式執行,結果發生了奇葩事項~
在Java環境下的工程中執行以下程式碼,正常輸出。
public class Test {
public static void main(String[] args) {
System.out.println(getNameFromFilename("C:/a/b/c.png"));
}
public static String getNameFromFilename(String filename) {
int dotPosition = filename.lastIndexOf('.');
if (dotPosition != -1) {
return filename.substring(0, dotPosition);
}
return "";
}
}
列印“C:/a/b/c”
在Android環境下的工程中,竟然直接把JVM搞崩潰了,不明所以啊~
Invalid layout of java.lang.String at value
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (javaClasses.cpp:129), pid=8236, tid=3188
# fatal error: Invalid layout of preloaded class
#
# JRE version: 7.0_17-b02
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.7-b01 mixed mode windows-amd64 compressed oops)
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# J:\AndroidCenter\MiCodeFileExplorer\hs_err_pid8236.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.sun.com/bugreport/crash.jsp
#
相關文章
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(8)-檔案排序工具類FileSortHelper原始碼排序
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(0)-初步研究原始碼
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(2)-2個單例項工具類原始碼單例
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(4)-檔案操作工具類FileOperationHelper原始碼
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(9)-入口分析原始碼
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(1)-2個模型Model原始碼模型
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(5)-AsyncTask非同步任務原始碼非同步
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(6)-媒體檔案MediaFile和檔案型別MimeUtils原始碼型別
- 小米開原始檔管理器MiCodeFileExplorer-原始碼研究(7)-Favorite收藏管理和SQLite資料庫CRUD原始碼SQLite資料庫
- JDK1.8原始碼(十一)——java.util.TreeMap類JDK原始碼Java
- Android 常用開發工具類原始碼Android原始碼
- java原始碼-java.util.ListJava原始碼
- 分析 java.util.Hashtable 原始碼Java原始碼
- jdbc Util 工具類JDBC
- 小米開源便籤Notes-原始碼研究(2)-定時提醒的便籤原始碼
- 原始碼管理:SVN原始碼管理器在ASP.NET VS中的使用注意事項原始碼ASP.NET
- PHP原始碼研究PHP原始碼
- ICE原始碼研究原始碼
- 07 併發工具類CountDownLatch、CyclicBarrier、Semaphore使用及原始碼分析CountDownLatch原始碼
- 併發工具類:Semaphore原始碼解讀原始碼
- FLASHCS3多檔案上傳原始碼(類似uccenter社群)S3原始碼
- 小米開源便籤Notes-原始碼研究(1)-匯出功能整體思路原始碼
- COLA的擴充套件性使用和原始碼研究套件原始碼
- Java 常用工具類 Collections 原始碼分析Java原始碼
- jdk原始碼閱讀(主要:util,lang,concurrent)(一)JDK原始碼
- Java java.util.HashMap實現原理原始碼分析JavaHashMap原始碼
- 原始碼加密工具原始碼加密
- Java 中使用 google.zxing 快捷生成二維碼(附工具類原始碼)JavaGo原始碼
- Foursquare 原始碼研究之---------使用者登入原始碼
- 集合原始碼分析[3]-ArrayList 原始碼分析原始碼
- SOFA 原始碼分析 — 連線管理器原始碼
- vue3 antvX6的使用原始碼Vue原始碼
- 【楊航】自動生成實體類工具原始碼原始碼
- CMultiFTP類原始碼 (轉)FTP原始碼
- Java集合類原始碼Java原始碼
- Vue原始碼探究-原始碼檔案組織Vue原始碼
- iOS開發原始碼閱讀篇--FMDB原始碼分析3(FMDatabaseQueue+FMDatabasePool)iOS原始碼Database
- 好的開原始碼原始碼