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.
MINOTES/other/07_210340142.段逸群_代码标注/tool/BackupUtils.java

351 lines
17 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.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.tool;
import android.content.Context;
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";
// Singleton stuff
private static BackupUtils sInstance;
public static synchronized BackupUtils getInstance(Context context) {
if (sInstance == null) {// 如果实例为空则创建新实例
sInstance = new BackupUtils(context);
} // 返回实例
return sInstance;
}
/**
* Following states are signs to represents backup or restore
* status
*/
// Currently, the sdcard is not mounted
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// The backup file not exist
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// The data is not well formated, may be changed by other programs
public static final int STATE_DATA_DESTROIED = 2;
// Some run-time exception which causes restore or backup fails
public static final int STATE_SYSTEM_ERROR = 3;
// Backup or restore success
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;// 查询结果中笔记id所在列的索引
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;// 定义以上数据列MIME类呼叫日期号码的索引初始值
private final String[] TEXT_FORMAT;// 定义带有3个元素字符串数组TEXT_FORMAT
private static final int FORMAT_FOLDER_NAME = 0;// 格式化后目录名称FORMAT_FOLDER_NAME= 0
private static final int FORMAT_NOTE_DATE = 1;
private static final int FORMAT_NOTE_CONTENT = 2;// 格式化后的笔记内容索引为2
private Context mContext;// 声名Context类型和字符串类型
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 = "";
}// 初始化文件路径mFileDirectory = ""为空
// 创建TextExport对象
private String getFormat(int id) {
return TEXT_FORMAT[id];
}
/**
* Export the folder identified by folder id to text
*/
private void exportFolderToText(String folderId, PrintStream ps) {
// Query notes belong to this folder
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 {
// Print note's last modified date
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// Query data belong to this note
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps);
} while (notesCursor.moveToNext());
}
notesCursor.close();
}
}
/**
* Export note identified by id to a print stream
*/
private void exportNoteToText(String noteId, PrintStream ps) {
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, // 查询CONTENT_DATA_URI对应的数据表
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] {
noteId
}, null);
// 使用DataColumns.NOTE_ID是否为限制查询条件并查询noted对应的数据行
if (dataCursor != null) {// 若查询不为空,则执行以下代码:
if (dataCursor.moveToFirst()) {// 移动游标为第一条记录并循环记录
do {
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);// 获取MIME_TYPE的值
if (DataConstants.CALL_NOTE.equals(mimeType)) {
// Print phone number
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
String location = dataCursor.getString(DATA_COLUMN_CONTENT);// 从记录中获取phonenumber和calldate的值并输出号码
if (!TextUtils.isEmpty(phoneNumber)) {// 若电话号码不为空
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
phoneNumber));// 输出电话号码输出到PrintStream实例PS中
}
// Print call date
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat
.format(mContext.getString(R.string.format_datetime_mdhm),
callDate)));// 输出通话日期信息到PrintStream中
// Print call attachment location
if (!TextUtils.isEmpty(location)) {// 若位置信息不为空
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
location));
} // 输出位置信息到PrintStream实例PS中
} else if (DataConstants.NOTE.equals(mimeType)) {// 若数据类型为Note则执行以下语句
String content = dataCursor.getString(DATA_COLUMN_CONTENT);// 从Cursor中获取信息
if (!TextUtils.isEmpty(content)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
content));// 将内容信息格式化输出rintStream实例PS中
}
}
} while (dataCursor.moveToNext());
}
dataCursor.close();
}
// print a line separator between note
try {
ps.write(new byte[] {
Character.LINE_SEPARATOR, Character.LETTER_NUMBER
});
} catch (IOException e) {// 若出现IO异常则廖永Log类的e方法将异常信息输出日志中
Log.e(TAG, e.toString());
}
}
// 使用rintStream实例PS的write方法写入字节数组到输出流中包括换行和字母数字
/**
* Note will be exported as text which is user readable
*/
public int exportToText() {// 定义exportToText(),返回值类型为整型
if (!externalStorageAvailable()) {
Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED;
}
// 若外部存储不可用输出日记信息返回表示Media was not mounted
PrintStream ps = getExportToTextPrintStream();// 获取打印输出
if (ps == null) {
Log.e(TAG, "get print stream error");
return STATE_SYSTEM_ERROR;
} // 若获取不到打印输出输出get print stream error",并返回错误
// First export folder and its notes
Cursor folderCursor = mContext.getContentResolver().query(// 声名Cursor类的变量folder存储调查结果
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, // 调用getContentResolver()查询目标为Note表中数据和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) {// 判断folder是否为空
if (folderCursor.moveToFirst()) {
do {
// Print folder's name
String folderName = "";// 遍历查询文件夹中所有文件夹记录
if (folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
folderName = mContext.getString(R.string.call_record_folder_name);// 若记录对应通话记录文件夹给folder赋值Notes.ID_CALL_RECORD_FOLDER
} else {// 否则folder赋值为记录的摘要字段值
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);// 获取当前记录对应文件夹id并赋值给folder
exportFolderToText(folderId, ps);
} while (folderCursor.moveToNext());// 将当前记录文件夹导出为文本形式结果写入PS中
}
folderCursor.close();
}
// Export notes in root's folder
Cursor noteCursor = mContext.getContentResolver().query(// 通过getContentResolver()获取resolver对象并调用querty方法查询
Notes.CONTENT_NOTE_URI, // 查询URI
NOTE_PROJECTION, // 查询列
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
+ "=0",
null, null);// 限制查询类型为Notes.TYPE_NOTE且父id为0的note记录
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))));// 根据时间格式化字符串的时间戳,将时间转换成字符串格式
// Query data belong to this note
String noteId = noteCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps);
} while (noteCursor.moveToNext());
} // 或i去当前Note记录的id吧id对应数据写入输出流中
noteCursor.close();
}
ps.close();// 关闭游标
return STATE_SUCCESS;
}
/**
* Get a print stream pointed to the file {@generateExportedTextFile}
*/
private PrintStream getExportToTextPrintStream() {
File file = generateFileMountedOnSDcard(mContext, R.string.file_path, // 使用getExportToTextPrintStream()再sd卡上生成指定名称和路径的文本文件
R.string.file_name_txt_format);
if (file == null) {
Log.e(TAG, "create file to exported failed");
return null;// 若生成文件失败返回null再logcat输出错误信息
}
mFileName = file.getName();
mFileDirectory = mContext.getString(R.string.file_path);// 将成功创建文件保存为FoleNAMe路径柏村委mFileDiectory
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(file);
ps = new PrintStream(fos);// 创建对象fos用于写入文件
} catch (FileNotFoundException e) {// 使用fos创建PrintStream对象PS一边向文件夹写入数据
e.printStackTrace();
return null;// 若无法找到写入目标文件再logcat输出错误信息并返回null
} catch (NullPointerException e) {
e.printStackTrace();
return null;
}
return ps;
}
}
/**
* Generate the text file to store imported data
*/
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder();
sb.append(Environment.getExternalStorageDirectory());// 再strtingbuilder中添加SD卡根目录路径
sb.append(context.getString(filePathResId));
File filedir = new File(sb.toString());// 添加文件路径字符串资源id并返回file对象表示该目录
sb.append(context.getString(
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis())));// 再StringBuilder添加文件名格式字符串资源id并使用dateFormat替换为当前日期格式化字符串
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();
} // 如果不能在指定目录下创建新的文件则抛出IOException异常
return null;
}
}