Log保存文件-Android
為什么80%的碼農都做不了架構師?>>> ??
前言
在開發過程中尤其是項目進入測試后,為了方便定位問題,經常需要將log保存下來,當然你可以自己寫個log輔助類又或者直接使用第三方的jar包,這里多多少少需要對系統的log類進行一些包裝,調用也不再是系統的log類,如果你只希望調用系統的log類又想打印的log能按自己的規則保存到文件那么請繼續往下看。
原理
首先啟動模擬器或者用手機連接電腦,進入命令行并且輸入如下命令
C:\Users\Administrator>adb shell root[@pisces](https://my.oschina.net/lazydomino):/ # logcat -v time *:W 05-01 17:10:48.619 W/PushService( 2216): 2015-05-01 17:10:48,620 - [WARN::PushService] - [Process:2216][Thread:1] Service called on timer 05-01 17:10:48.622 W/PushService( 2216): 2015-05-01 17:10:48,623 - [WARN::PushService] - [Process:2216][Thread:31] SMACK 05:10:48 下午 SENT (1122316296): <iq to='xiaomi.com' id='0' chid='0' type='get'><ping xmlns='urn:xmpp:ping'><pf><p>t:69</p></pf></ping></iq> 05-01 17:10:48.622 W/PushService( 2216): 05-01 17:10:48.701 W/PushService( 2216): 2015-05-01 17:10:48,701 - [WARN::PushService] - [Process:2216][Thread:428] SMACK 05:10:48 下午 RCV (1122316296): <iq chid='0' id='0' type='result'/> 05-01 17:11:03.638 W/PushService( 2216): 2015-05-01 17:11:03,637 - [WARN::PushService] - [Process:2216][Thread:31] JOB: check the ping-pong. 05-01 17:11:08.384 W/MountService( 960): getVolumeState(/storage/emulated/0/external_sd): Unknown volume 05-01 17:11:08.385 W/MountService( 960): getVolumeState(/mnt/sdcard-ext): Unknown volume 05-01 17:11:08.386 W/MountService( 960): getVolumeState(/mnt/ext_sdcard): Unknown volume 05-01 17:11:08.387 W/MountService( 960): getVolumeState(/mnt/sdcard2): Unknown volume上面的命令過濾出了所有的w以及w優先級以上的log(本人D等級打印太多所以選用W),按“Ctrl + c”終止剛才的命令,然后再執行如下命令
C:\Users\Administrator>adb shell root[@pisces](https://my.oschina.net/lazydomino):/ # logcat -v time *:W >> /sdcard/log.log logcat -v time *:W > sdcard/log.log這時候你再去設備的sd卡根目錄看看,是不是多出來個“log.log”文件,打開看看里面的內容是不是我們保存的log。
是的,這里我們要用到的就是上面的方式,既然命令行中的log可以保存的文件中,那我們只需要在程序中執行命令行即可
logcat
關于logcat的用法可以通過如下命令查看
C:\Users\Administrator>adb shell root[@pisces](https://my.oschina.net/lazydomino):/ # logcat --help logcat --help Usage: logcat [options] [filterspecs] options include:-s Set default filter to silent.Like specifying filterspec '*:s'-f <filename> Log to file. Default to stdout-r [<kbytes>] Rotate log every kbytes. (16 if unspecified). Requires -f-n <count> Sets max number of rotated logs to <count>, default 4-v <format> Sets the log print format, where <format> is one of:brief process tag thread raw time threadtime long-c clear (flush) the entire log and exit-d dump the log and then exit (don't block)-t <count> print only the most recent <count> lines (implies -d)-g get the size of the log's ring buffer and exit-b <buffer> Request alternate ring buffer, 'main', 'system', 'radio'or 'events'. Multiple -b parameters are allowed and theresults are interleaved. The default is -b main -b system.-B output the log in binary filterspecs are a series of<tag>[:priority]where <tag> is a log component tag (or * for all) and priority is:V VerboseD DebugI InfoW WarnE ErrorF FatalS Silent (supress all output)'*' means '*:d' and <tag> by itself means <tag>:vIf not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS. If no filterspec is found, filter defaults to '*:I'If not specified with -v, format is set from ANDROID_PRINTF_LOG or defaults to "brief"從logcat help可以看出,logcat本身就提供了保存文件的參數“-f <filename>”,你可能要問為什么不用直接這個保存,主要是logcat也有它的局限性,從上面可以看出,logcat提供了根據tag和priority的過濾器,但如果我們想把項目中的所有log都保存到文件中,那我們就不得不將所有的tag都添加到過濾器中,這時候如果可以根據應用程序的包名或者進程ID過濾就省事多了,所以我們有用到了grep命令。
grep
grep命令的用法如下
root[@pisces](https://my.oschina.net/lazydomino):/ # grep grep usage: grep [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]][-e pattern] [-f file] [--binary-files=value] [--color=when][-e pattern] [-f file] [--binary-files=value] [--color=when][--context[=num]] [--directories=action] [--label] [--line-buffered][pattern] [file ...]grep命令不僅支持關鍵字過濾還支持正則,這里我們要用到的就是他的正則過濾。
使用方法
再試試如下命令
logcat -v time *:W | grep '( 960):' >> /sdcard/log.txt注: 關鍵字"'( 960):'"中的進程ID請修改為你系統中存在的ID號,最好直接從“logcat -v time *:W”命令輸出的log中復制粘貼,另外“()”中有五個字符,進程ID長度不夠在前面補空格
對比下SD中的log.log和log.txt你會發現log.log中包含了所有進程warn和warn以上優先級的log而log.txt中只包含了指定關鍵字的log。所以我們只需根據“logcat -v time *:W”打印的log的規則再配合grep命令的正則表達式是可以根據進程ID過濾的。遺憾的是本人嘗試了很多次始終由于grep無法完全支持正則表達式而未能得到一個完全匹配的正則表達式,目前只得到以下表達式,雖然不能做到百分百的過濾但也算比較靠譜,如果你寫出來了麻煩也告訴我一下yxmsw2007@gmail.com
logcat -v time *:W | grep '^.*\/.*( 960):' >> /sdcard/log.logLogService
package com.example.service;import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Comparator; import java.util.Date; import java.util.List;import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Environment; import android.os.IBinder; import android.os.PowerManager; import android.os.StatFs; import android.os.PowerManager.WakeLock; import android.os.StrictMode; import android.util.Log;/*** @project SampleAndroid * @class LogService * @description * 日志服務,日志默認會存儲在內存中的安裝目錄下面并且系統每隔一段時間就會檢測一下log文件的大小,* 如果log文件超過指定的大小則會執行如下動作:* 1.SD卡不可用,所有log文件都保存在內存中,當log文件數超出指定的數量就會刪除較早的log* 2.SD卡可用而且存儲空間足夠則將文件移動SD卡中,并檢測SD中保存的文件是否都在指定時間日期內,如果不是則刪除* 3.SD卡可用但存儲空間小于指定的大小,在操作log前會先刪除SD卡中的所有log并重新檢測空間,如果空間仍不足則按1操作否則按2進行* @author yxmsw2007* @version 1.0* @email yxmsw2007@gmail.com * @data 2015-5-1 下午8:18:27 */ public class LogService extends Service {private static final String TAG = LogService.class.getSimpleName();private static final int MEMORY_LOG_FILE_MAX_SIZE = 10 * 1024 * 1024; // 內存中日志文件最大值,10Mprivate static final int MEMORY_LOG_FILE_MONITOR_INTERVAL = 10 * 60 * 1000; // 內存中的日志文件大小監控時間間隔,10分鐘private static final int MEMORY_LOG_FILE_MAX_NUMBER = 2; // 內存中允許保存的最大文件個數private static final int SDCARD_LOG_FILE_SAVE_DAYS = 7; // sd卡中日志文件的最多保存天數private static final String LOG_FOLDER = "Log"; //日志文件夾private static final String MONITOR_LOG_PRIORITY = "D"; // 監聽日志的最低優先級private static final String MONITOR_LOG_SIZE_ACTION = "MONITOR_LOG_SIZE"; // 日志文件大小監測action/*** logcat -v time *:D | grep -n '^.*\/.*( 828):' >> /sdcard/download/Log.log*/private static String LOG_FILTER_COMMAND_FORMAT = "logcat -v time *:%s | grep '^.*\\/.*(%s):' >> %s";private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HHmmss");// 日志名稱格式private String mLogFileDirMemory; // 日志文件在內存中的路徑(日志文件在安裝目錄中的路徑)private String mLogFileDirSdcard; // 日志文件在sdcard中的路徑private String mCurrLogFileName; // 如果當前的日志寫在內存中,記錄當前的日志文件名稱private Process process;private WakeLock wakeLock;private PendingIntent mMemoryLogFileSizeMonitor; private AlarmManager mAlarmManager;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "-- onCreate() --");if (android.os.Build.VERSION.SDK_INT > 9) {StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();StrictMode.setThreadPolicy(policy);} // 注冊SD卡狀態監聽廣播IntentFilter sdCarMonitorFilter = new IntentFilter();sdCarMonitorFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);sdCarMonitorFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);sdCarMonitorFilter.addDataScheme("file");registerReceiver(mSDStateReceiver, sdCarMonitorFilter);IntentFilter logTaskFilter = new IntentFilter();logTaskFilter.addAction(MONITOR_LOG_SIZE_ACTION); //注冊日志大小監聽廣播logTaskFilter.addAction(Intent.ACTION_TIME_CHANGED); //如果時間被重新設置,要判斷當前時間是否在有效時間內,//如果超出了范圍需要將日志保存到新文件中,否則會被清除registerReceiver(mLogTaskReceiver, logTaskFilter);// 部署日志大小監控任務Intent intent = new Intent(MONITOR_LOG_SIZE_ACTION);mMemoryLogFileSizeMonitor = PendingIntent.getBroadcast(this, 0, intent, 0);mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),MEMORY_LOG_FILE_MONITOR_INTERVAL, mMemoryLogFileSizeMonitor);PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);new LogCollectorThread().start();}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "-- onDestroy() --");if (process != null) {process.destroy();}// 取消日志大小監控任務mAlarmManager.cancel(mMemoryLogFileSizeMonitor);unregisterReceiver(mSDStateReceiver);unregisterReceiver(mLogTaskReceiver);}/*** 日志收集 * 1.清除日志緩存 * 2.殺死應用程序已開啟的Logcat進程防止多個進程寫入一個日志文件 * 3.開啟日志收集進程 * 4.處理日志文件 移動 OR 刪除*/class LogCollectorThread extends Thread {public LogCollectorThread() {super("LogCollectorThread");Log.d(TAG, "LogCollectorThread is create");}@Overridepublic void run() {try {wakeLock.acquire(); // 喚醒手機clearLogCache();List<String> orgProcessList = getAllProcess();List<ProcessInfo> processInfoList = getProcessInfoList(orgProcessList);killLogcatProc(processInfoList);mCurrLogFileName = dateToFileName(new Date());//獲取新的日志文件名稱createLogCollector(getMemoryFilePath(mCurrLogFileName));Thread.sleep(1000);// 休眠,創建文件,然后處理文件,不然該文件還沒創建,會影響文件刪除handleLog(mCurrLogFileName);wakeLock.release(); // 釋放} catch (Exception e) {e.printStackTrace();}}}/*** 每次記錄日志之前先清除日志的緩存, 不然會在兩個日志文件中記錄重復的日志*/private void clearLogCache() {Log.d(TAG, "-- clearLogCache() --");Process proc = null;List<String> commandList = new ArrayList<String>();commandList.add("logcat");commandList.add("-c");try {proc = Runtime.getRuntime().exec(commandList.toArray(new String[commandList.size()]));StreamConsumer errorGobbler = new StreamConsumer(proc.getErrorStream());StreamConsumer outputGobbler = new StreamConsumer(proc.getInputStream());errorGobbler.start();outputGobbler.start();if (proc.waitFor() != 0) {Log.e(TAG, " clearLogCache proc.waitFor() != 0");}} catch (Exception e) {Log.e(TAG, "clearLogCache failed", e);} finally {try {proc.destroy();} catch (Exception e) {Log.e(TAG, "clearLogCache failed", e);}}}/*** 關閉由本程序開啟的logcat進程: 根據用戶名稱殺死進程(如果是本程序進程開啟的Logcat收集進程那么兩者的USER一致)* 如果不關閉會有多個進程讀取logcat日志緩存信息寫入日志文件* @param allProcList* @return*/private void killLogcatProc(List<ProcessInfo> allProcList) {Log.d(TAG, "-- killLogcatProc() --");if (process != null) {process.destroy();}String packName = this.getPackageName();String myUser = getAppUser(packName, allProcList);for (ProcessInfo processInfo : allProcList) {if (processInfo.name.toLowerCase().equals("logcat")&& processInfo.user.equals(myUser)) {android.os.Process.killProcess(Integer.parseInt(processInfo.pid));}}}/*** 獲取本程序的用戶名稱* @param packName* @param allProcList* @return*/private String getAppUser(String packName, List<ProcessInfo> allProcList) {for (ProcessInfo processInfo : allProcList) {if (processInfo.name.equals(packName)) {return processInfo.user;}}return null;}/*** 根據ps命令得到的內容獲取PID,User,name等信息* @param orgProcessList* @return*/private List<ProcessInfo> getProcessInfoList(List<String> orgProcessList) {List<ProcessInfo> procInfoList = new ArrayList<ProcessInfo>();for (int i = 1; i < orgProcessList.size(); i++) {String processInfo = orgProcessList.get(i);String[] proStr = processInfo.split(" ");// USER PID PPID VSIZE RSS WCHAN PC NAME// root 1 0 416 300 c00d4b28 0000cd5c S /initList<String> orgInfo = new ArrayList<String>();for (String str : proStr) {if (!"".equals(str)) {orgInfo.add(str);}}if (orgInfo.size() == 9) {ProcessInfo pInfo = new ProcessInfo();pInfo.user = orgInfo.get(0);pInfo.pid = orgInfo.get(1);pInfo.ppid = orgInfo.get(2);pInfo.name = orgInfo.get(8);procInfoList.add(pInfo);}}return procInfoList;}/*** 運行PS命令得到進程信息* @return USER PID PPID VSIZE RSS WCHAN PC NAME * root 1 0 416 300 c00d4b28 0000cd5c S /init*/private List<String> getAllProcess() {List<String> orgProcList = new ArrayList<String>();Process proc = null;try {proc = Runtime.getRuntime().exec("ps");StreamConsumer errorConsumer = new StreamConsumer(proc.getErrorStream());StreamConsumer outputConsumer = new StreamConsumer(proc.getInputStream(), orgProcList);errorConsumer.start();outputConsumer.start();if (proc.waitFor() != 0) {Log.e(TAG, "getAllProcess proc.waitFor() != 0");}} catch (Exception e) {Log.e(TAG, "getAllProcess failed", e);} finally {try {proc.destroy();} catch (Exception e) {Log.e(TAG, "getAllProcess failed", e);}}return orgProcList;}/*** eg: logcat -v time *:D | grep -n '^.*\/.*( 828):' >> /sdcard/download/Log.log* @param priority* @param path* @return*/private String getLogFilterCommand(String priority, String path) {Log.d(TAG, "-- getLogFilterCommand() --");String sid = "" + android.os.Process.myPid();for (int i = sid.length(); i < 5; i++) {sid = " " + sid;}return String.format(LOG_FILTER_COMMAND_FORMAT, priority, sid, path);}/*** 開始收集日志信息*/public void createLogCollector(String path) {Log.d(TAG, "-- createLogCollector() --");String command = getLogFilterCommand(MONITOR_LOG_PRIORITY, path.replace(" ", "\\ "));//獲取命令Log.d(TAG, command);List<String> commandList = new ArrayList<String>();commandList.add("sh");commandList.add("-c");commandList.add(command);try {process = Runtime.getRuntime().exec(commandList.toArray(new String[commandList.size()]));// process.waitFor();} catch (Exception e) {Log.e(TAG, "CollectorThread == >" + e.getMessage(), e);}}/*** 處理日志文件 */public void handleLog(String currFileName) {Log.d(TAG, "-- handleLog() --");moveLogfile(currFileName);//將內存中日志文件轉移到SD中,當前正在記錄的日志文件除外deleteSdcardExpiredLog(SDCARD_LOG_FILE_SAVE_DAYS);//刪除SD中過期的日志文件deleteMemoryExpiredLog(MEMORY_LOG_FILE_MAX_NUMBER, currFileName);//刪除內存中過期的日志文件}/*** 檢查日志文件大小是否超過了規定大小 如果超過了重新開啟一個日志收集進程*/private void checkLogSize() {Log.d(TAG, "-- checkLogSize() --");if (mCurrLogFileName != null && !"".equals(mCurrLogFileName)) {String path = getMemoryFilePath(mCurrLogFileName);File file = new File(path);if (!file.exists()) {return;}if (file.length() >= MEMORY_LOG_FILE_MAX_SIZE) {Log.d(TAG, "The log's size is too big!");new LogCollectorThread().start();}}}/*** 將日志文件轉移到SD卡下面*/private void moveLogfile(String currFileName) {Log.d(TAG, "-- moveLogfile() --");if (!isSdcardAvailable()) {return;}File file = new File(getMemoryDirPath());if (!file.isDirectory()) {return;}File[] allFiles = file.listFiles();for (File logFile : allFiles) {String fileName = logFile.getName();if (currFileName.equals(fileName)) {continue;}if (logFile.length() >= getSdcardAvailableSize()) {deleteSdcardAllLog();}if (logFile.length() >= getSdcardAvailableSize()) {return;}if (copy(logFile, new File(getSdcardFilePath(fileName)))) {logFile.delete();Log.d(TAG, "move file success, log name is:" + fileName);}}}/*** 刪除SD卡中所有日志文件*/private void deleteSdcardAllLog() {Log.d(TAG, "-- deleteSdcardAllLog() --");if (isSdcardAvailable()) {File file = new File(getSdcardDirPath());if (file.isDirectory()) {File[] allFiles = file.listFiles();for (File logFile : allFiles) {logFile.delete();Log.d(TAG, "delete file success, file name is:" + logFile.getName());}}}}/*** 刪除SD內過期的日志*/private void deleteSdcardExpiredLog(int days) {Log.d(TAG, "-- deleteSdcardExpiredLog() --");if (isSdcardAvailable()) {File file = new File(getSdcardDirPath());File[] allFiles = file.listFiles();for (File logFile : allFiles) {if (canDeleteSDLog(logFile.getName(), days)) {logFile.delete();Log.d(TAG, "delete file success, file name is:" + logFile.getName());}}}}/*** * @param createDateStr* @return*//*** 判斷sdcard上的日志文件是否可以刪除,規則:文件創建時間是否在days天數內* @param fileName 文件名* @param days 天數* @return*/public boolean canDeleteSDLog(String fileName, int days) {Calendar calendar = Calendar.getInstance();calendar.add(Calendar.DAY_OF_MONTH, -1 * days);// 刪除7天之前日志Date expiredDate = calendar.getTime();try {Date createDate = fileNameToDate(fileName);return createDate.before(expiredDate);} catch (ParseException e) {Log.e(TAG, e.getMessage(), e);}return false;}/*** 刪除內存中的過期日志,刪除規則: 保存最近的number個日志文件* @param number 保留的文件個數*/private void deleteMemoryExpiredLog(int number, String currFileName) {Log.d(TAG, "-- deleteMemoryExpiredLog() --");File file = new File(getMemoryDirPath());if (file.isDirectory()) {File[] allFiles = file.listFiles();Arrays.sort(allFiles, new FileComparator());for (int i = 0; i < allFiles.length - number; i++) {File f = allFiles[i];if (f.getName().equals(currFileName)) {continue;}f.delete();Log.d(TAG, "delete file success, file name is:" + f.getName());}}}/*** 拷貝文件* @param source* @param target* @return*/private boolean copy(File source, File target) {FileInputStream in = null;FileOutputStream out = null;try {if (!target.exists()) {boolean createSucc = target.createNewFile();if (!createSucc) {return false;}}in = new FileInputStream(source);out = new FileOutputStream(target);byte[] buffer = new byte[8 * 1024];int count;while ((count = in.read(buffer)) != -1) {out.write(buffer, 0, count);}return true;} catch (Exception e) {Log.e(TAG, e.getMessage(), e);return false;} finally {try {if (in != null) {in.close();}if (out != null) {out.close();}} catch (IOException e) {Log.e(TAG, e.getMessage(), e);return false;}}}class ProcessInfo {public String user;public String pid;public String ppid;public String name;@Overridepublic String toString() {return "user=" + user + " pid=" + pid + " ppid=" + ppid + " name=" + name;}}class StreamConsumer extends Thread {InputStream is;List<String> list;StreamConsumer(InputStream is) {this.is = is;}StreamConsumer(InputStream is, List<String> list) {this.is = is;this.list = list;}public void run() {try {InputStreamReader isr = new InputStreamReader(is);BufferedReader br = new BufferedReader(isr);String line = null;while ((line = br.readLine()) != null) {if (list != null) {list.add(line);}}} catch (IOException ioe) {ioe.printStackTrace();}}}/*** 監控SD卡狀態*/private BroadcastReceiver mSDStateReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {String action = intent.getAction();Log.d(TAG, "mLogTaskReceiver: " + action);if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) { // 存儲卡被卸載} else { // 存儲卡被掛載}}};/*** 監控日志大小*/private BroadcastReceiver mLogTaskReceiver = new BroadcastReceiver() {public void onReceive(Context context, Intent intent) {String action = intent.getAction();Log.d(TAG, "mLogTaskReceiver: " + action);if (MONITOR_LOG_SIZE_ACTION.equals(action)) {checkLogSize();} else if (Intent.ACTION_TIME_CHANGED.equals(action)) {if (canDeleteSDLog(mCurrLogFileName, SDCARD_LOG_FILE_SAVE_DAYS)) {Log.d(TAG, "The log is out of date !");new LogCollectorThread().start();}}}};private class FileComparator implements Comparator<File> {public int compare(File file1, File file2) {try {Date create1 = fileNameToDate(file1.getName());Date create2 = fileNameToDate(file2.getName());if (create1.before(create2)) {return -1;} else {return 1;}} catch (ParseException e) {return 0;}}}/*** SD卡是否可用* @return*/private boolean isSdcardAvailable() {return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);}/*** SD卡剩余空間* @return*/private long getSdcardAvailableSize() {if (isSdcardAvailable()) {String path = Environment.getExternalStorageDirectory().getAbsolutePath();StatFs fileStats = new StatFs(path);fileStats.restat(path);return fileStats.getAvailableBlocksLong() * fileStats.getBlockSizeLong();}return 0;}public boolean creatDir(String path) {File f = new File(path);return f.exists() && f.isDirectory() || f.mkdirs();}public boolean creatFile(String path) {if (path != null && path.contains(File.separator) && creatDir(path.substring(0, path.lastIndexOf(File.separator)))) {File f = new File(path);try {return f.exists() && f.isFile() || f.createNewFile();} catch (IOException e) {Log.w(TAG, e);}}return false;}/*** 日志文件名轉日期* @param fileName* @return* @throws ParseException*/private Date fileNameToDate(String fileName) throws ParseException {fileName = fileName.substring(0, fileName.indexOf("."));//去除文件的擴展類型(.log)return sdf.parse(fileName);}/*** 日期轉日志文件名* @param date* @return*/private String dateToFileName(Date date) {return sdf.format(date) + ".log";//日志文件名稱}/*** 文件在內存中的路徑* @param fileName* @return*/private String getMemoryFilePath(String fileName) {return getMemoryDirPath() + File.separator + fileName;}/*** 內存中日志文件保存目錄* @return*/private String getMemoryDirPath() {if (mLogFileDirMemory == null) {mLogFileDirMemory = getFilesDir().getAbsolutePath() + File.separator + LOG_FOLDER;creatDir(mLogFileDirMemory);}return mLogFileDirMemory;}/*** 文件在SD中的路徑* @param fileName* @return*/private String getSdcardFilePath(String fileName) {return getSdcardDirPath() + File.separator + fileName;}/*** SD卡中日志文件保存目錄* @return*/private String getSdcardDirPath() {if (mLogFileDirSdcard == null && isSdcardAvailable()) {mLogFileDirSdcard = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator+ getString(R.string.app_name)+ File.separator+ LOG_FOLDER;creatDir(mLogFileDirSdcard);}return mLogFileDirSdcard;}}源碼下載
SampleAndroid
參考資料
android 寫log到文件
轉載于:https://my.oschina.net/noke/blog/1506859
總結
以上是生活随笔為你收集整理的Log保存文件-Android的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS端JSON转Model链式编程框架
- 下一篇: Android Gallery和Imag