爲什麼要將Log寫入文件
運行應用程序的時候,大多數是不會連接着IDE的;
而當應用程序崩潰時,我們需要收集復現步驟,在設備上覆現,並進行Debug;
而由於Android手機的多樣性,有些問題是某個機型特有的, 這樣很難去復現;
所以我們想能不能把重要的log輸出在文件中,有問題,有bug直接把log發過來,這樣可以大大簡化復現的流程,增加Debug的速度。
原理簡介
其實原理很簡單,就是把一行行字符串寫入文件中而已。
這裏選用了靜態方法調用,跟系統的log一樣,使用起來比較方便;
需要注意的是,使用之前需要傳入context進行初始化,這樣是爲了獲得系統規定好的存儲路徑,將數據寫入Android希望我們寫入的地方,便於卸載時清除;
其實也可以不傳入context,直接用Environment的靜態方法獲取外部儲存路徑,自定義文件名即可,但是這樣比較不規範,不推薦這樣做;
代碼很簡單,分享在CSDN上方便以後使用。
權限
<!--外部存儲讀取權限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
源碼:
GitHub地址:
package com.waka.workspace.logtofile;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* 將Log日誌寫入文件中
* <p>
* 使用單例模式是因爲要初始化文件存放位置
* <p>
* Created by waka on 2016/3/14.
*/
public class LogToFile {
private static String TAG = "LogToFile";
private static String logPath = null;//log日誌存放路徑
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US);//日期格式;
private static Date date = new Date();//因爲log日誌是使用日期命名的,使用靜態成員變量主要是爲了在整個程序運行期間只存在一個.log文件中;
/**
* 初始化,須在使用之前設置,最好在Application創建時調用
*
* @param context
*/
public static void init(Context context) {
logPath = getFilePath(context) + "/Logs";//獲得文件儲存路徑,在後面加"/Logs"建立子文件夾
}
/**
* 獲得文件存儲路徑
*
* @return
*/
private static String getFilePath(Context context) {
if (Environment.MEDIA_MOUNTED.equals(Environment.MEDIA_MOUNTED) || !Environment.isExternalStorageRemovable()) {//如果外部儲存可用
return context.getExternalFilesDir(null).getPath();//獲得外部存儲路徑,默認路徑爲 /storage/emulated/0/Android/data/com.waka.workspace.logtofile/files/Logs/log_2016-03-14_16-15-09.log
} else {
return context.getFilesDir().getPath();//直接存在/data/data裏,非root手機是看不到的
}
}
private static final char VERBOSE = 'v';
private static final char DEBUG = 'd';
private static final char INFO = 'i';
private static final char WARN = 'w';
private static final char ERROR = 'e';
public static void v(String tag, String msg) {
writeToFile(VERBOSE, tag, msg);
}
public static void d(String tag, String msg) {
writeToFile(DEBUG, tag, msg);
}
public static void i(String tag, String msg) {
writeToFile(INFO, tag, msg);
}
public static void w(String tag, String msg) {
writeToFile(WARN, tag, msg);
}
public static void e(String tag, String msg) {
writeToFile(ERROR, tag, msg);
}
/**
* 將log信息寫入文件中
*
* @param type
* @param tag
* @param msg
*/
private static void writeToFile(char type, String tag, String msg) {
if (null == logPath) {
Log.e(TAG, "logPath == null ,未初始化LogToFile");
return;
}
String fileName = logPath + "/log_" + dateFormat.format(new Date()) + ".log";//log日誌名,使用時間命名,保證不重複
String log = dateFormat.format(date) + " " + type + " " + tag + " " + msg + "\n";//log日誌內容,可以自行定製
//如果父路徑不存在
File file = new File(logPath);
if (!file.exists()) {
file.mkdirs();//創建父路徑
}
FileOutputStream fos = null;//FileOutputStream會自動調用底層的close()方法,不用關閉
BufferedWriter bw = null;
try {
fos = new FileOutputStream(fileName, true);//這裏的第二個參數代表追加還是覆蓋,true爲追加,flase爲覆蓋
bw = new BufferedWriter(new OutputStreamWriter(fos));
bw.write(log);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();//關閉緩衝流
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}