目录
一.内部存储数据
二.外部存储数据
三.共享首选项
四.远程位置访问数据
一.内部存储数据
- 存储数据方法:
- 使用 内部存储器 存储数据
- 使用 外部存储器 存储数据
- 使用 共享首选项 存储数据
- 从 远程位置访问 数据
1.使用 内部存储器 存储数据
- 内部存储 ≠ 内存,内部存储特点:
- 只能被创建自己的应用访问,数据信息私有
- 应用卸载后,内部存储中的文件也被删除
- 内部存储空间耗尽,手机就无法使用
- java.io 包 提供各种类 访问本地文件:将数据写入文件、从文件中读取数据
- I/O 数据流分类:
- input 输入流:读取 和应用关联的私有文件,使用 openFileInput()方法
- output 输出流:写入 和应用关联的私有文件,使用 openFileOutput()方法
- 文件保存在: /data/data/<package name>/files/内部存储文件,与其他资源(如图像)分组在一起
2.output 输出流
- 读取 /data/data/<package name>/files文件夹 的文件,可供对此文件夹具有 读访问权 的应用访问
- 将数据从应用中输出,执行过程:
- android.content.Context类 openFileOutput() 方法:打开或创建文件(输出流)
- java.io.FileOutputStream类 write() 方法:将数据写入文件中
- java.io.FileOutputStream类 close() 方法:关闭文件(一定要记得关闭!)
- 文件创建模式,创建后仅能被本机访问,两种创建模式:
- MODE_PRIVATE: 文件不存在,则创建文件,文件存在,则写入内容覆盖源文件(默认模式)
- MODE_APPEND: 文件不存在,则创建文件,文件存在,则写入内容追加在原来的后面
- FileOutputStream类
- void close() :关闭输出流
- void write(byte[] buffer, int offset, int byteCount):写入一个字节流,从第几个字节开始写,一共写几个字节
- void write(byte[] buffer):写入全部内容
- void write(int oneByte):写入一个字节,字节所在的序列号
- 区分字节流 / 字符流:字节流适用于任何数据格式,字符流仅适用于字符串
3.input 输入流
- 写入 /data/data/<package name>/files文件夹 的文件,可供对此文件夹具有写访问权 的应用访问
- 打开内部存储文件 读取数据,执行步骤:
- android.content.Context类 openFileInput() 方法:打开文件
- java.io.FileInputStream类 read() 方法:从文件读取数据
- java.io.FileInputStream类 close() 方法:关闭文件(一定要记得关闭!)
- FileInputStream类
- int available():当前可读取的字节数
- int read(byte[] buffer):读取全部内容
- int read(byte[] buffer, int offset, int byteCount):读取一个字节流,从第几个字节开始读,一共读几个字节
- long skip(long byteCount):跳过多少字节不读
4.将静态文件作为资源使用
- android.content.Context类 提供方法,提高文件操作效率:
- getFilesDir() :获取文件路径:data/data/包名
- getDir(String dirname, int mode):在内部存储文件中打开现有目录
- deleteFile(String filename):删除目录
- fileList():获取文件列表
- 静态文件: 应用程序包中的 只读文件,一旦创建无法更改,位置: res/raw
- getResources() 方法:获取静态资源文件
- openRawResource() 方法:读取静态文件的流
5.实现文件的写入、读取、清空
public class MainActivity extends Activity {
// ...声明各组件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
read = (Button) findViewById(R.id.btnRead);
// ...获取各组件,设置监听器
ButtonListener listener = new ButtonListener();
// ...}
class ButtonListener implements OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnWrite: // 写入操作 writeToFile(文件名,文件内容)
writeToFile(etFile.getText().toString(), etContent.getText().toString());
break;
case R.id.btnRead: // 读取操作
if ("".equals(etFile.getText().toString())) { // 文件名为空 读取静态资源
BufferedInputStream bis = null; // 创建一个缓冲流用于实现读取
try { // 获取并读取静态资源文件的流
InputStream is = getResources().openRawResource(R.raw.introduction);
bis = new BufferedInputStream(is); // 实例化缓冲流
byte[] data = new byte[bis.available()]; // 流中可读的字节组
bis.read(data); // 读取字节组
String s = new String(data);
tvDisplay.setText(s); // 读取到的内容设置到显示内容上
} catch (Exception e) {
Log.e("MainActivity", e.getMessage());
} finally { // 关闭流 不可或缺的部分!!
try {
if (bis != null)
bis.close();
} catch (IOException e) {
Log.e("MainActivity", e.getMessage());
}}
}else { // 文件名不为空,根据文件名读取文件
readFromFile(etFile.getText().toString());
}
break;
case R.id.btnClear: // 清空操作
etFile.setText("");
etContent.setText("");
break;
}}}
void readFromFile(String filename) {
FileInputStream fis = null; // FileInputStream 输入流
try {
fis = openFileInput(filename);
fis.read(data);
String s = new String(data);
tvDisplay.setText(s);
Log.e("file", "readFromFile读取成功");
} catch (Exception e) {
Log.e("MainActivity", e.getMessage());
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException e) {
Log.e("MainActivity", e.getMessage());
}}}
void writeToFile(String filename, String content) { // 写入文件
FileOutputStream fos = null; // FileOutputStream 输出流
try {
fos = openFileOutput(filename, MODE_APPEND); // 文件存在就追加内容
fos.write(content.getBytes()); // 转换为字节组执行写操作
Toast.makeText(MainActivity.this, "写入成功!", Toast.LENGTH_LONG).show();
Log.e("file", "writeToFile写入成功");
} catch (Exception e) {
Log.e("MainActivity", e.getMessage()); // 若发生异常 获取异常写入日志
} finally { // 为了关闭流,正常或不正常都要执行finally
try {
fos.close(); // 使用完流一定关闭流
} catch (IOException e) {
Log.e("MainActivity", e.getMessage());
}}}}
- 写入文件:
- 读取自己写入的文件:
- 读取静态文件:
- 静态资源位置:
二.外部存储数据
1.外部存储设备定义
- SD 卡:外部存储设备之一,存储容量 远高于 内部存储设备,其所有文件公共
- 下图显示了 DDMS 透视图的 File Explorer 选项卡中可用的 sdcard 文件夹:/mnt/sdcard/fileName
- mnt就是mount的缩写,
2.外部存储设备可用性
- android.os.Environment类String getExternalStorageState() 获取外部存储设备状态的常量:
常量
描述
MEDIA_MOUNTED
介质已经存在并加载,且可读可写
MEDIA_REMOVED
介质不存在
MEDIA_UNMOUNTED
SD卡存在,但不被手机识别
MEDIA_MOUNTED_READ_ONLY
介质已经存在并加载,但只能读
- Environment类获取外部存储设备信息 的方法有:
- getDataDirectory():获取外部存储设备数据目录
- getExternalStorageDirectory():获取外部存储设备路径(使用最多)
- getExternalStoragePublicDirectory(String type):获取外部存储设备公共路径,如闹钟
- getExternalStorageState():获取外部存储设备状态
- getRootDirectory():获取外部存储设备根目录
- isExternalStorageEmulated():true:设备不具有外部存储器不可用,false:设备可用
- isExternalStorageRemovable():外部存储设备是否可以被移除
3.外部存储设备读写
- 对 SD卡进行读取写入,需要用 Environment类的 getExternalStorageDirectory() 方法 获取外部存储设备路径
- 数据读取和写入过程 与 内部存储文件读取写入过程 相同
- 对外部存储设备读取或写入前,要在 AndroidManifest.xml文件 中指定权限
- SD卡读写步骤:
- 判断 外部存储设备 是否加载成功 并可访问
- 获取 外部存储器的 存储路径
- 使用 输入/输出流 进行 文件读写
- 在 AndroidManifest.xml 添加权限
public class MainActivity extends Activity {
// 声明组件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取组件并设置监听....
void readFromFile(String filename) {
String state = Environment.getExternalStorageState(); // 判断SD卡状态
if (state.equals(Environment.MEDIA_MOUNTED)) { // 如果SD卡加载好并可读写
String path = Environment.getExternalStorageDirectory() + "/" + filename;
FileInputStream fis =null;
try {
fis = new FileInputStream(path);
byte[] data=new byte[fis.available()];
fis.read(data);
String s = new String(data);
tvDisplay.setText(s);
//....}
void writeToFile(String filename, String content) {
String state = Environment.getExternalStorageState(); // 判断SD卡状态
if (state.equals(Environment.MEDIA_MOUNTED)) { // SD卡加载好,并且可读可写
String path = Environment.getExternalStorageDirectory()
+ "/" + filename; // /mnt/sdcard/andy.txt
FileOutputStream fos= null;
try {
fos = new FileOutputStream(path, true); // true表示通过追加的方式写入文件
fos.write(content.getBytes());
Toast.makeText(MainActivity.this, "写入成功!", Toast.LENGTH_LONG).show();
} catch (Exception e) {
//...}
class ButtonListener implements OnClickListener {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnWrite:
writeToFile(etFile.getText().toString(), etContent.getText().toString());
break;
case R.id.btnRead:
readFromFile(etFile.getText().toString());
break;
case R.id.btnClear:
etFile.setText("");
etContent.setText("");
break;
}}}}
4.内部存储器 VS 外部存储器
- 内部存储器
- 文件是应用专用
- 卸载应用时文件自动移除
- 存储空间有限
- 存储路径:/data/data/程序包名/files文件夹
- 外部存储器
- 文件是公共的
- 卸载应用时SD卡数据保留
- SD 卡的存储容量 远高于 内部存储设备 并且可扩展
- 存储路径:/mnt/sdcard文件夹
三.共享首选项
- 共享首选项: 安卓提供、最简单的方式、永久保存数据,比如应用默认设置
- 以键值对方式 存储数据,相当于 Map集合
- 两种偏好设置:
- 活动级首选项:一项活动只有一个首选项
- 应用程序级首选项:一个应用可有多个首选项
- android.content.SharedPreferences接口,保存和检索 内置数据类型的键 - 值对
- SharedPreferences接口 支持的数据类型: boolean、 float、 int、 long、 String、,没有 integer
- 想要将整数数据写入共享首选项,使用以下哪个选项?
- putInteger()、setInteger()、putInt()、setInt()
- 检索共享偏好设置:
- 应用级共享首选项:getSharedPreferences(String filename,int Mode),定义xml文件名
- 活动级共享首选项:getPreferences(int Mode),以活动名作为xml文件名
- Mode 操作模式(不止下面三种):
- MODE_PRIVATE:默认操作模式,文件私有,只能本应用访问
- MODE_WORLD_READABLE:文件可被其他应用读取
- MODE_WORLD_WRITEABLE:文件可被其他应用写入
- 共享偏好设置存储在:data /data /包名 /shared_prefs /xxx.xml
- 共享首选项不需要提供权限设置
- 修改共享首选项,需要使用 SharedPreferences.Editor接口,提供的方法有:
- commit():不可或缺,否则无效
- putXXX(String key, XXX value):添加
- SharedPreferences接口:getXXX()...,SharedPreferences.Editor接口:putXXX(),commit(),如下图所示:
public class MainActivity extends Activity {
// 声明组件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取组件....
SharedPreferences sp1=getSharedPreferences("login",MODE_PRIVATE); // 获取接口
// 第二个参数表示若没有该项信息,返回的替换值
String user=sp1.getString("username",null); // 调用 getXXX方法,根据键获取值
String pwd=sp1.getString("password",null); // 调用 getXXX方法,根据键获取值
etUser.setText(user);
etPwd.setText(pwd);
login.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(cb.isChecked()){ // 判断记住密码复选框是否选中
SharedPreferences sp=getSharedPreferences("login",MODE_PRIVATE);
Editor editor=sp.edit(); // edit方法获取编辑器对象,用于编辑偏好设置
//以键-值得形式写入数据
editor.putString("username",etUser.getText().toString());
editor.putString("password",etPwd.getText().toString());
editor.commit(); // 提交写入数据
Toast.makeText(MainActivity.this,"记住成功!",
Toast.LENGTH_SHORT).show();
}}});}}
四.远程位置访问数据
- java.net.URL类 访问 因特网上的资源
- 从 URL类指定的资源读取数据,需要创建 URLConnection类,创建链接
- 从 URLConnection类的对象读取数据过程 与 从其他输入流中读取数据过程 相同
- 要在 AndroidManifest.xml 文件中指定权限,以下哪个选项来实现此需求?
- <uses-permission> <uses-permissions> <use-permission> <use-permissions>
- 远程位置访问数据,需要在系统配置文件中添加权限:允许访问因特网、允许写入sd卡
public class MainActivity extends Activity {
Button download;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
download=(Button)findViewById(R.id.download);
download.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Toast.makeText(MainActivity.this,"开始下载!",Toast.LENGTH_SHORT).show();
DownloadThread t=new DownloadThread(); // 调用自己写的下载类,执行下载任务
t.start();
}});}
class DownloadThread extends Thread{ // 该线程类封装任务:实现下载和写入sd卡,自己写的
@Override
public void run() {
String urlpath ="http://img.jk51.com/img_jk51/78037076.jpeg"; // 自定义资源地址
try{
URL url=new URL(urlpath); // 获取 URL对象
URLConnection con=url.openConnection(); // 获取 URL链接
InputStream is=con.getInputStream(); // 获取输入流用于读取/下载数据
BufferedInputStream bis=new BufferedInputStream(is); // 缓冲流 提高效率
String state=Environment.getExternalStorageState(); // 获取sd卡状态
if(state.equals(Environment.MEDIA_MOUNTED)){ // 当sd卡可以存储时
// /mnt/sdcard/xwz.jpg 获取外部存储路径
String path=Environment.getExternalStorageDirectory()+"/dog.jpg";
FileOutputStream fos=new FileOutputStream(path); // 输出流 写入
int i;
while((i=bis.read())!=-1){ // 读不到的时候,值是-1,能读到就写入
fos.write(i); // 写入文件
}}
}catch(Exception e){
Log.e("MainActivity",e.getMessage()); // 后面还缺关闭流操作
}}}}