You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xiaomibianqian/BackupUtils.java

348 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 版权所有 (c) 2010-2011, The MiCode 开源社区 (www.micode.net)
*
* 根据 Apache License, Version 2.0(“许可证”)获得许可;
* 除非遵守许可证,否则不得使用此文件。
* 您可以在以下网址获得许可证的副本:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 除非适用法律要求或书面同意,否则根据许可证分发的软件以“原样”分发,
* 没有任何明示或暗示的保证,包括但不限于适销性、针对特定用途的适用性等任何明示或暗示的保证。
* 请参阅许可证以获取有关许可下的权利和限制的特定语言。
*/
package net.micode.notes.tool; // 定义包名
import android.content.Context; // Android 上下文类
import android.database.Cursor; // 数据库游标
import android.os.Environment; // 外部存储环境类
import android.text.TextUtils; // 文本工具类
import android.text.format.DateFormat; // 日期格式化工具类
import android.util.Log; // 日志工具类
import net.micode.notes.R; // 资源类
import net.micode.notes.data.Notes; // 笔记数据类
import net.micode.notes.data.Notes.DataColumns; // 笔记数据列类
import net.micode.notes.data.Notes.DataConstants; // 笔记数据常量类
import net.micode.notes.data.Notes.NoteColumns; // 笔记列类
import java.io.File; // 文件类
import java.io.FileNotFoundException; // 文件未找到异常
import java.io.FileOutputStream; // 文件输出流
import java.io.IOException; // 输入输出异常
import java.io.PrintStream; // 打印流
public class BackupUtils {
private static final String TAG = "BackupUtils"; // 日志标签
// 单例模式相关
private static BackupUtils sInstance; // 单例对象
// 获取单例对象
public static synchronized BackupUtils getInstance(Context context) {
if (sInstance == null) {
sInstance = new BackupUtils(context); // 如果为空则新建一个实例
}
return sInstance; // 返回单例对象
}
/**
* 以下状态用于表示备份或恢复的状态
*/
// 当前sd卡未挂载
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// 备份文件不存在
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// 数据格式不正确,可能被其他程序更改
public static final int STATE_DATA_DESTROIED = 2;
// 运行时异常导致备份或恢复失败
public static final int STATE_SYSTEM_ERROR = 3;
// 备份或恢复成功
public static final int STATE_SUCCESS = 4;
private TextExport mTextExport; // 文本导出器
// 构造函数
private BackupUtils(Context context) {
mTextExport = new TextExport(context); // 初始化文本导出器
}
// 检查外部存储是否可用
private static boolean externalStorageAvailable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
// 导出到文本
public int exportToText() {
return mTextExport.exportToText(); // 调用文本导出器的导出方法
}
// 获取导出文本文件名
public String getExportedTextFileName() {
return mTextExport.mFileName; // 返回文本导出器的文件名
}
// 获取导出文本文件目录
public String getExportedTextFileDir() {
return mTextExport.mFileDirectory; // 返回文本导出器的文件目录
}
// 内部类:文本导出器
private static class TextExport {
// 笔记查询投影数组
private static final String[] NOTE_PROJECTION = {
NoteColumns.ID,
NoteColumns.MODIFIED_DATE,
NoteColumns.SNIPPET,
NoteColumns.TYPE
};
// 数据列索引
private static final int NOTE_COLUMN_ID = 0;
private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
private static final int NOTE_COLUMN_SNIPPET = 2;
// 数据查询投影数组
private static final String[] DATA_PROJECTION = {
DataColumns.CONTENT,
DataColumns.MIME_TYPE,
DataColumns.DATA1,
DataColumns.DATA2,
DataColumns.DATA3,
DataColumns.DATA4,
};
// 数据列索引
private static final int DATA_COLUMN_CONTENT = 0;
private static final int DATA_COLUMN_MIME_TYPE = 1;
private static final int DATA_COLUMN_CALL_DATE = 2;
private static final int DATA_COLUMN_PHONE_NUMBER = 4;
// 文本格式数组
private final String [] TEXT_FORMAT;
// 文本格式索引
private static final int FORMAT_FOLDER_NAME = 0;
private static final int FORMAT_NOTE_DATE = 1;
private static final int FORMAT_NOTE_CONTENT = 2;
private Context mContext; // Android 上下文
private String mFileName; // 文件名
private String mFileDirectory; // 文件目录
// 构造函数
public TextExport(Context context) {
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); // 初始化文本格式
mContext = context; // 初始化上下文
mFileName = ""; // 初始化文件名
mFileDirectory = ""; // 初始化文件目录
}
// 获取指定格式字符串
private String getFormat(int id) {
return TEXT_FORMAT[id]; // 返回文本格式数组中的字符串
}
/**
* 将指定文件夹ID的文件夹导出为文本
*/
private void exportFolderToText(String folderId, PrintStream ps) {
// 查询属于此文件夹的笔记
Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
folderId
}, null);
if (notesCursor != null) {
if (notesCursor.moveToFirst()) {
do {
// 打印笔记的最后修改日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// 查询属于此笔记的数据
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps); // 导出笔记到文本
} while (notesCursor.moveToNext());
}
notesCursor.close(); // 关闭游标
}
}
/**
* 将指定ID的笔记导出到打印流
*/
private void exportNoteToText(String noteId, PrintStream ps) {
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI,
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] {
noteId
}, null);
if (dataCursor != null) {
if (dataCursor.moveToFirst()) {
do {
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
if (DataConstants.CALL_NOTE.equals(mimeType)) {
// 打印电话号码
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
String location = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(phoneNumber)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
phoneNumber));
}
// 打印通话日期
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat
.format(mContext.getString(R.string.format_datetime_mdhm),
callDate)));
// 打印通话附件位置
if (!TextUtils.isEmpty(location)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
location));
}
} else if (DataConstants.NOTE.equals(mimeType)) {
String content = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(content)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
content));
}
}
} while (dataCursor.moveToNext());
}
dataCursor.close(); // 关闭游标
}
// 打印笔记之间的分隔线
try {
ps.write(new byte[] {
Character.LINE_SEPARATOR, Character.LETTER_NUMBER
});
} catch (IOException e) {
Log.e(TAG, e.toString()); // 记录错误日志
}
}
/**
* 将笔记导出为用户可读的文本
*/
public int exportToText() {
if (!externalStorageAvailable()) {
Log.d(TAG, "Media was not mounted"); // 记录日志:媒体未挂载
return STATE_SD_CARD_UNMOUONTED; // 返回状态sd卡未挂载
}
PrintStream ps = getExportToTextPrintStream(); // 获取打印流
if (ps == null) {
Log.e(TAG, "get print stream error"); // 记录日志:获取打印流错误
return STATE_SYSTEM_ERROR; // 返回状态:系统错误
}
// 首先导出文件夹及其笔记
Cursor folderCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,"(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND "
+ NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
if (folderCursor != null) {
if (folderCursor.moveToFirst()) {
do {
// 打印文件夹的名称
String folderName = "";
if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
folderName = mContext.getString(R.string.call_record_folder_name);
} else {
folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
}
if (!TextUtils.isEmpty(folderName)) {
ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName));
}
String folderId = folderCursor.getString(NOTE_COLUMN_ID);
exportFolderToText(folderId, ps); // 导出文件夹到文本
} while (folderCursor.moveToNext());
}
folderCursor.close(); // 关闭游标
}
// 导出根文件夹中的笔记
Cursor noteCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
+ "=0", null, null);
if (noteCursor != null) {
if (noteCursor.moveToFirst()) {
do {
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// 查询属于此笔记的数据
String noteId = noteCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps); // 导出笔记到文本
} while (noteCursor.moveToNext());
}
noteCursor.close(); // 关闭游标
}
ps.close(); // 关闭打印流
return STATE_SUCCESS; // 返回状态:成功
}
/**
* 获取指向导出文本文件的打印流
*/
private PrintStream getExportToTextPrintStream() {
File file = generateFileMountedOnSDcard(mContext, R.string.file_path,
R.string.file_name_txt_format);
if (file == null) {
Log.e(TAG, "create file to exported failed"); // 记录日志:创建导出文件失败
return null;
}
mFileName = file.getName(); // 设置文件名
mFileDirectory = mContext.getString(R.string.file_path); // 设置文件目录
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(file); // 创建文件输出流
ps = new PrintStream(fos); // 创建打印流
} catch (FileNotFoundException e) {
e.printStackTrace(); // 打印堆栈跟踪
return null;
} catch (NullPointerException e) {
e.printStackTrace(); // 打印堆栈跟踪
return null;
}
return ps; // 返回打印流
}
}
/**
* 在挂载的SD卡上生成用于存储导入数据的文本文件
*/
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder(); // 创建字符串构建器
sb.append(Environment.getExternalStorageDirectory()); // 追加外部存储目录
sb.append(context.getString(filePathResId)); // 追加文件路径资源ID
File filedir = new File(sb.toString()); // 创建文件目录
sb.append(context.getString( // 追加格式化后的文件名
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis())));
File file = new File(sb.toString()); // 创建文件
try {
if (!filedir.exists()) { // 如果文件目录不存在
filedir.mkdir(); // 创建目录
}
if (!file.exists()) { // 如果文件不存在
file.createNewFile(); // 创建新文件
}
return file; // 返回文件
} catch (SecurityException e) {
e.printStackTrace(); // 打印堆栈跟踪
} catch (IOException e) {
e.printStackTrace(); // 打印堆栈跟踪
}
return null; // 返回null
}
}