目录
一.内部存储数据
- 存储数据方法:
- 使用 内部存储器 存储数据
- 使用 外部存储器 存储数据
- 使用 共享首选项 存储数据
- 从 远程位置访问 数据
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()); // 后面还缺关闭流操作 }}}}
![]()