内部存储
# 硬件 [RAM && ROM && SD Card]
- RAM就是普通所谓的计算机内存,是和CPU配套用来运行操作系统和程序的
- 我们用来存储文件的区域只能是ROM或SD Card
- ROM里一般用于存储操作系统文件和app应用程序,相当于Windows的C盘 【读写速度快,价格高】
- SD卡一般容量有几十G,可以存放一些大的文件,比如照片、视频、地图离线包等 【速度慢,价格低,容量高】
# 内部存储 Internal Storage
·概述
- 安卓系统为每个app创建一个私有目录,这个目录只能被该app自己访问,别的app不能访问。
- 通常内部存储就是在ROM上。
- 通常把小型的、需要快速加载的数据存储在内部存储(即私有目录)下
·操作
- 获取这个目录的位置:getFilesDir()
// 查看本app的私有目录
File appDir = getFilesDir();
Log.d(TAG, "本APP的私有目录为:" + appDir);
- 文件读写
File appDir = getFilesDir();
File f = new File(appDir, "abc.txt");
FileOutputStream fstream = new FileOutputStream(f);
# 外部存储 External Storage
· 概述
- 以前的安卓手机都是插一张SD卡作为外部存储,
现在的安卓手机都内部自带了一块存储,不需要外插SD卡了。
- 这个位置是所有app都能访问的。
- 大型文件放在外部存储里(即SD卡)里
· 数据目录
- 数据目录获取 //··· /storage/emulated/0/Android/data/example.demo0902/files
File appDataDir = getExternalFilesDir("");
- 子目录获取 // ··· /storage/emulated/0/Android/data/example.demo0902/files/movie
File movieDir = getExternalFilesDir("movie");
movieDir.mkdirs();
· 公共目录
- 在SD卡有一些公共目录,各app都会访问这些公共目录
- // 公共目录, /storage/emulated/0
File publicDir = Environment.getExternalStoragePublicDirectory("");
- // 图片目录, /storage/emulated/0/Pictures
File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
- // 相机目录 (DCIM: Digital Camera In Memory ) ,/storage/emulated/0/DCIM
File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
- // 音乐目录, /storage/emulated/0/Music
File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
# 添加权限
· 概述:要读写 app自己的数据目录,并不需要添加权限。
要读写外部存储的上其他位置,例如,访问DCIM下的文件,需要添加权限 。
· 添加过程
- 声明权限 [在 AndroidManifest.xml里添加]
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-- 通常为了简单起见,我们只声明 WRITE_EXTERNAL_STORAGE 就够了,因为能WRITE就包含了READ的权限。
- 申请权限 [应用启动时手工向用户申请批准]
// 检查和申请权限
public void checkPermissions(){}
// 处理用户返回的结果
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults){}
- 相关博客:
# 代码示例·内部存储
package example.demo0901;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class MainActivity extends AppCompatActivity
{
final String TAG = "测试";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 查看本app的私有目录
File appDir = getFilesDir();
Log.d(TAG, "本APP的私有目录为:" + appDir);
// 加载数据
try
{
loadData();
Toast.makeText(this, "已加载数据", Toast.LENGTH_SHORT).show();
} catch (Exception e)
{
Log.w(TAG, "无法加载数据!");
}
}
// 点击 '保存' 按钮
public void doSave( View view )
{
String text = ((EditText)findViewById(R.id.id_edittext)).getText().toString();
// 在私有目录下创建文件abc.txt,然后往里面写入一个字符串
File appDir = getFilesDir();
File f = new File(appDir, "abc.txt");
FileOutputStream fstream = null;
try{
fstream = new FileOutputStream(f);
fstream.write( text.getBytes("UTF-8"));//写入字符串
}catch(Exception e){
}
finally {
try{ fstream.close();} catch (Exception e2){}
}
Toast.makeText(this, "已保存", Toast.LENGTH_SHORT).show();//提示信息
}
// 读取私有目录下的abc.txt
// 注:这里故意展示不同的写法,给大家的参考
private void loadData () throws Exception
{
File f = new File( getFilesDir(), "abc.txt");
FileInputStream fstream = null;
try{
fstream = new FileInputStream(f);
byte[] data = new byte[1024]; // 当文件很大时,应分作多次读取, 这里是简易写法仅作演示
int n = fstream.read(data);
if(n> 0)
{
// 当读取的到byte[]转成String
String str = new String(data,0, n, "UTF-8");
((EditText)findViewById(R.id.id_edittext)).setText(str);
Log.d(TAG, "加载内容: " + str);
}
}finally
{
try{ fstream.close();}catch (Exception e){}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="example.demo0901.MainActivity">
<EditText
android:id="@+id/id_edittext"
android:layout_width="368dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="请输入"
android:inputType="textPersonName"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:onClick="doSave"
android:text="保存"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/id_edittext"/>
</android.support.constraint.ConstraintLayout>
# 代码示例·外部存储
package example.demo0902;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
public class MainActivity extends AppCompatActivity
{
final String TAG = "测试 MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 在SD卡上有一个app的数据目录, /storage/emulated/0/Android/data/example.demo0902/files
File appDataDir = getExternalFilesDir("");
Log.d(TAG, "外部数据目录为: " + appDataDir);
// 公共目录, /storage/emulated/0
File publicDir = Environment.getExternalStoragePublicDirectory("");
// 图片目录, /storage/emulated/0/Pictures
File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
// 相机目录 (DCIM: Digital Camera In Memory ) ,/storage/emulated/0/DCIM
File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
// 音乐目录, /storage/emulated/0/Music
File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
Log.d(TAG, "图片目录为: " + picDir);
Log.d(TAG, "相机目录为: " + dcimDir);
Log.d(TAG, "音乐目录为: " + musicDir);
Log.d(TAG, "公共目录为: " + publicDir);
// 如果要读写外部内存上的其他位置,如DCIM下的文件,都是需要申请权限的
// (1) 在AndroidManifest.xml里声明权限,
// (2) 在这里调用checkPermissions()来请用户给予授权!
// checkPermissions();
}
// 点击 '保存' 按钮
public void doSave (View view)
{
String text = ((EditText)findViewById(R.id.id_edittext)).getText().toString();
File f = new File(getExternalFilesDir(""), "abc.txt");
FileOutputStream fstream = null;
try{
fstream = new FileOutputStream(f);
fstream.write( text.getBytes("UTF-8"));
}catch(Exception e)
{
}
finally
{
try{ fstream.close();} catch (Exception e2){}
}
Toast.makeText(this, "已保存", Toast.LENGTH_SHORT).show();
}
// 检查和申请权限
final int PERMISSION_REQ_CODE = 1;
public void checkPermissions()
{
// 要申请的权限列表
final String[] permissions = {
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
// 检查本应用是否有了 WRITE_EXTERNAL_STORAGE 权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)
{
// 系统将弹出一个对话框,询问用户是否授权
ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQ_CODE);
}
}
// 权限申请的结果
// requestCode:请求码
// permissions: 申请的N个权限
// grantResults: 每个权限是否被授权
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
{
if(requestCode == PERMISSION_REQ_CODE)
{
for(int i=0; i<permissions.length;i++)
{
if(grantResults[i] != PackageManager.PERMISSION_GRANTED)
{
// 惨,用户没给我们授权...这意味着有此功能就不能用了
}
}
}
}
}