Internal 内部存储区
External 外部存储区
一些设备把持久的存储空间分为了 intenal 和 external 分区,所以即使没有可移除的存储媒介,也有两种存储空间,并且不管是不是可移除的,API 的行为也是一致的
app 默认安装到 Internal 存储区,可通过清单文件中的android:installLocation
属性更改
卸载 app 时,系统会移除internal中你的app的所有文件 (Internal)
系统移除你app在通过 getExternalFilesDir() 方法取到的目录中的文件 (External)
data/data/app_name/
. 打开目录
getFilesDir() 返回一个代表 internal 目录的 File 对象
getDir(name,mode) 在 internal 目录中创建或者打开一个目录
getCacheDir() 返回一个用于存放你的 app 临时 缓存文件的 internal 目录
File file = new File(getApplicationContext().getFilesDir(), filename);
. 写文件
fos.write(content.getBytes());
将字符串 content 写入文件public void save(View view) {
EditText et_input = (EditText) findViewById(R.id.et_input);
String content = et_input.getText().toString();
String filename = "data.txt";
FileOutputStream fos;
try {
fos = openFileOutput(filename, Context.MODE_PRIVATE);
fos.write(content.getBytes());
fos.close();
Toast.makeText(this, getString(R.string.success), Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
. 写一个缓存文件
public File getTempFile(Context context, String url) {
File file = null;
try {
String filename = Uri.parse(url).getLastPathSegment(); //从 URL 中提取文件名
assert filename != null; //断言,这里为 true 后边的语句才会执行
file = File.createTempFile(filename, null, context.getCacheDir());
//在指定目录中创建前缀为 filename,后缀为 null 的空文件
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
. 打开一个已存在的文件
byte[] buffer = new byte[fis.available()]; //测试 byte 数组的大小
fis.read(buffer);
content = new String(buffer);
还有
//按字符读
int ch;
ch = fis.read();
while(ch != -1) {
fileContent += (char)ch;
ch = fis.read();
}
public void getInfo(View view) {
String filename = "data.txt";
FileInputStream fis;
EditText et_input = (EditText) findViewById(R.id.et_input);
String content = null;
try {
fis = openFileInput(filename);
byte[] buffer = new byte[fis.available()]; //测试 byte 数组的大小
fis.read(buffer);
content = new String(buffer);
et_input.setText(content);
fis.close();
Toast.makeText(this, getString(R.string.success), Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
. 获取外部存储的访问权限
在 manifest 中声明权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
. 校验外部存储可用
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
|| Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)
. 保存文件到公共目录
public File getExternalDir(String directoryName) {
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), directoryName);
//File file = Environment.getExternalStoragePublicDirectory(directoryName);
if (!file.exists()) {
if(!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
}
return file;
}
.nomedia
空文件,媒体扫描程序就无法读取你的媒体文件file.getAbsolutePath()
获取文件绝对路径 (外部存储位置). 保存应用私有文件
public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e("LOG_TAG", "Directory not created");
}
return file;
}
注:不管 public 还是 private ,用类似 DIRECTORY_PICTURES 这样的 API 常量来创建能够确保文件被系统正确对待
. 保存缓存文件
. 查询剩余空间
. 删除文件
myContext.deleteFile(fileName);
. 获取Shared Preferences的handle (创建)
Context context = getActivity();
SharedPreferences sharedPref = context.getSharedPreferences(
getString(R.string.preference_file_key), Context.MODE_PRIVATE);
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
. 写入Shared Preferences
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(getString(R.string.saved_high_score), newHighScore);
editor.commit();
. 从Shared Preferences中读取数据
int defaultValue = getResources().getInteger(R.string.saved_high_score_default);
int highScore = sharedPref.getInt(getString(R.string.saved_high_score), defaultValue);
. 例 保存登录账号密码
即,关闭应用后再次打开会
public class Utils {
public static boolean saveUserInfo(Context context, String account, String password) {
SharedPreferences sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("username", account);
editor.putString("password", password);
return editor.commit();
}
public static Map<String, String> getUserInfo(Context context) {
SharedPreferences sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE);
Map<String, String> userMap = new HashMap<>();
userMap.put("username", sharedPref.getString("username", null)); //若取不到,null作为默认值取出
userMap.put("password", sharedPref.getString("password", null));
return userMap;
}
}
Map<String, String> userInfo = Utils.getUserInfo(this);
if(userInfo != null) {
etAccount.setText(userInfo.get("username"));
etPassword.setText(userInfo.get("password"));
}
public void login(View view) {
String number = etAccount.getText().toString().trim();
String password = etPassword.getText().toString();
if(TextUtils.isEmpty(number)) { //系统提供的类 TextUtils
Toast.makeText(this, "请输入账号", Toast.LENGTH_SHORT).show();
return;
}
if(TextUtils.isEmpty(password)) {
Toast.makeText(this, "请输入密码", Toast.LENGTH_SHORT).show();
return;
}
Toast.makeText(this, "登陆成功", Toast.LENGTH_SHORT).show();
boolean isSaveSuccess = Utils.saveUserInfo(this, number, password);
if(isSaveSuccess) {
Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show();
}
}
. XML序列化过程描述
File file = new File(Environment.getExternalStorageDirectory(),"Person.xml");
FileOutputStream fos = new FileOutputStream(file);
XmlSerializer serializer = Xml.newSerializer();
1.设置文件编码方式:serializer.setOutput(fos,"utf-8");
2.写入xml文件的开始标签:serializer.startDocument("utf-8",true); 第一个参数设置文档的编码格式,第二个参数设置是否是一个独立的文档,一般设置为true
3.依次写入各元素 (如果有多个元素则可以使用迭代的方式写入,如果标签是嵌套的,则在写入顺序上也是嵌套的):
a) 写入开始标签:serializer.startTag(null,"Persons"); 命名空间,没有可以用null;标签名
b) 如果该标签有属性:serializer.attribute(null,"id",1); 命名空间;属性名;属性值
c) 写入元素内容:serializer.text(person.getName()); 该参数为实例对象中的某个属性值
d) 写入结束标签:serializer.endTag(null,"Persons"); 命名空间,一般为null;结束标签的标签名
4.文档的写入结束:serializer.endDocument()
5.通过 serializer.flush() 将流写入文件中
最后,关闭输出流:fos.close()
. PULL解析过程
Xml.newPullParser() 或 XmlPullParserFactory.newInstance().newPullParser()
abstract void setInput(Reader in) 该方法的源为字符流
abstract void setInput(InputStream inputStream, String inputEncoding) 字节流;编码
parser.getEventType()
首先打开虚拟机,
adb shell
sqlite3 数据库名 //打开或创建数据库
//若省略数据库名,则创建临时数据库,退出时删除该库
点命令:1.命令名和点之间没有空白符 2.必须在同一行 3.不能在普通SQL语句中 4.不接受注释
.databases 列出数据库
.tables 列出数据库中的表
chcp 65001
把控制台的字符编码切换为utf-8
的编码. 定义 schema 与 contract
. 使用SQL Helper创建数据库
实现 SQLiteOpenHelper 类的例子
public class FeedReaderDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "FeedReader.db";
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
}
}
//实例化
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
注:其中 onCreate 方法并没有实际创建或打开数据库,实际是在调用 getReadableDatabase 或 getWriteableDatabase 时.
. 对数据库中的数据进行操作
SQLiteDatabase db = helper. getWritableDatabase();
. 把信息放入数据库 增
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_CONTENT, content);
long newRowId;
newRowId = db.insert(FeedEntry.TABLE_NAME, FeedEntry.COLUMN_NAME_NULLABLE, values);
. 从数据库中读取信息 查
String[] projection = {
FeedEntry._ID,
FeedEntry.COLUMN_NAME_TITLE,
FeedEntry.COLUMN_NAME_UPDATED,
...
};
String sortOrder =
FeedEntry.COLUMN_NAME_UPDATED + " DESC";
Cursor c = db.query(
FeedEntry.TABLE_NAME, // The table to query
projection, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
//cursor 起始位置在 -1 处
cursor.moveToFirst(); //将读取点放在入口位置,read position
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedEntry._ID)
);
List itemIds = new ArrayList<>();
while(cursor.moveToNext()) {
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedEntry._ID));
itemIds.add(itemId);
}
cursor.close();
rawQuery
. 从数据库中删除信息 删
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) };
db.delete(table_name, selection, selectionArgs);
. 更新一个数据库
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) };
int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);
所谓事务,就是针对数据库的一组操作,具有原子性
若有语句没能成功执行,则已执行的语句发生回滚
db.beginTransaction();
try {
...
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
End.