目录

一.内部存储数据

二.外部存储数据

三.共享首选项

四.远程位置访问数据

一.内部存储数据

  • 存储数据方法:
  1. 使用 内部存储器 存储数据
  2. 使用 外部存储器 存储数据
  3. 使用 共享首选项 存储数据
  4. 从 远程位置访问 数据

1.使用 内部存储器 存储数据

  • 内部存储 ≠ 内存,内部存储特点:      
  1. 只能被创建自己的应用访问,数据信息私有     
  2. 应用卸载后,内部存储中的文件也被删除       
  3. 内部存储空间耗尽,手机就无法使用    
  • java.io 包 提供各种类 访问本地文件将数据写入文件从文件中读取数据
  • I/O 数据流分类:           
  1. input 输入流:读取 和应用关联的私有文件,使用 openFileInput()方法
  2. output 输出流:写入 和应用关联的私有文件,使用 openFileOutput()方法
  • 文件保存在: /data/data/<package name>/files/内部存储文件,与其他资源(如图像)分组在一起

2.output 输出流

  • 读取 /data/data/<package name>/files文件夹 的文件,可供对此文件夹具有 读访问权 的应用访问
  • 将数据从应用中输出,执行过程:
  1. android.content.Context类 openFileOutput() 方法:打开或创建文件(输出流)
  2. java.io.FileOutputStream类 write() 方法:将数据写入文件中
  3. java.io.FileOutputStream类 close() 方法:关闭文件(一定要记得关闭!)
  • 文件创建模式,创建后仅能被本机访问,两种创建模式:
  1. MODE_PRIVATE: 文件不存在,则创建文件,文件存在,则写入内容覆盖源文件(默认模式)
  2. MODE_APPEND: 文件不存在,则创建文件,文件存在,则写入内容追加在原来的后面
  • FileOutputStream类
  1. void close() :关闭输出流
  2. void write(byte[] buffer, int offset, int byteCount):写入一个字节流,从第几个字节开始写,一共写几个字节
  3. void write(byte[] buffer):写入全部内容
  4. void write(int oneByte):写入一个字节,字节所在的序列号
  • 区分字节流 / 字符流:字节流适用于任何数据格式,字符流仅适用于字符串

3.input 输入流

  • 写入 /data/data/<package name>/files文件夹 的文件,可供对此文件夹具有写访问权 的应用访问
  • 打开内部存储文件 读取数据,执行步骤:
  1. android.content.Context类 openFileInput() 方法:打开文件
  2. java.io.FileInputStream类 read() 方法:从文件读取数据
  3. java.io.FileInputStream类 close() 方法:关闭文件(一定要记得关闭!)
  • FileInputStream类
  1. int available():当前可读取的字节数
  2. int read(byte[] buffer):读取全部内容
  3. int read(byte[] buffer, int offset, int byteCount):读取一个字节流,从第几个字节开始读,一共读几个字节
  4. long skip(long byteCount):跳过多少字节不读

4.将静态文件作为资源使用

  • android.content.Context类 提供方法,提高文件操作效率:
  1. getFilesDir() :获取文件路径:data/data/包名
  2. getDir(String dirname, int mode):在内部存储文件中打开现有目录
  3. deleteFile(String filename):删除目录
  4. 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类获取外部存储设备信息 的方法有:
  1. getDataDirectory():获取外部存储设备数据目录
  2. getExternalStorageDirectory():获取外部存储设备路径(使用最多)
  3. getExternalStoragePublicDirectory(String type):获取外部存储设备公共路径,如闹钟
  4. getExternalStorageState():获取外部存储设备状态
  5. getRootDirectory():获取外部存储设备根目录
  6. isExternalStorageEmulated():true:设备不具有外部存储器不可用,false:设备可用
  7. isExternalStorageRemovable():外部存储设备是否可以被移除

3.外部存储设备读写

  • 对 SD卡进行读取写入,需要用 Environment类的 getExternalStorageDirectory() 方法 获取外部存储设备路径
  • 数据读取和写入过程 与 内部存储文件读取写入过程 相同
  • 对外部存储设备读取或写入前,要在 AndroidManifest.xml文件 中指定权限
  • SD卡读写步骤:
  1. 判断 外部存储设备 是否加载成功 并可访问
  2. 获取 外部存储器的 存储路径
  3. 使用 输入/输出流 进行 文件读写
  4. 在 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 外部存储器

  • 内部存储器
  1. 文件是应用专用
  2. 卸载应用时文件自动移除
  3. 存储空间有限
  4. 存储路径:/data/data/程序包名/files文件夹
  • 外部存储器
  1. 文件是公共的
  2. 卸载应用时SD卡数据保留
  3. SD 卡的存储容量 远高于 内部存储设备 并且可扩展
  4. 存储路径:/mnt/sdcard文件夹

三.共享首选项

  • 共享首选项: 安卓提供、最简单的方式、永久保存数据,比如应用默认设置
  • 以键值对方式 存储数据,相当于 Map集合
  • 两种偏好设置:
  1. 活动级首选项:一项活动只有一个首选项
  2. 应用程序级首选项:一个应用可有多个首选项
  • android.content.SharedPreferences接口,保存和检索 内置数据类型的键 - 值对
  • SharedPreferences接口 支持的数据类型: boolean、 float、 int、 long、 String、,没有 integer
  • 想要将整数数据写入共享首选项,使用以下哪个选项?
  • putInteger()、setInteger()、putInt()、setInt()
  • 检索共享偏好设置:
  1. 应用级共享首选项:getSharedPreferences(String filename,int Mode),定义xml文件名
  2. 活动级共享首选项:getPreferences(int Mode),以活动名作为xml文件名
  • Mode 操作模式(不止下面三种):
  1. MODE_PRIVATE:默认操作模式,文件私有,只能本应用访问
  2. MODE_WORLD_READABLE:文件可被其他应用读取
  3. 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()); // 后面还缺关闭流操作
			}}}}