【File 与 IO 存储】


1、Android的数据存储基本上没有什么更新的内容,我们可以将Java中的那一套File和Io体系拿过来直接使用,仅仅有一些边缘性的东西要介绍一下,所以这部分内容,首先将新的内容讲解一下,主要部分放在实例上面,通过实例,我们能够快速地掌握这部分知识

2、我们知道在手机中存储器一般分为两部分:手机内置的存储区(相对较小),可插拔的SD卡存储区(可扩展相对较大),但是现在有的手机比如小米3,它不支持可插拔的SD卡,也就是说,小米3 将SD直接焊接在内部了,不能够认为的更换,但是小米3的16G存储区中,依然分为:内置存储目录即/data/data/和SD卡存储目录;

3、一般来说我们的手机上的安装的每个应用的数据都分为两大类,一些数据存放在/data/data/<Package name>/files目录下,这些数据一般是比较重要的初始化数据等,我们称之为数据文件夹;另外一部分数据存放在SD卡目录下即/mnt/sdcard/目录下,这部分数据一般是应用程序存储的一些外部数据,比如文件、图片等等,我们称之为SD卡文件夹

4、好了,上面的问题搞清楚之后,就继续往下看:

(1)Java中的那一套File和IO,在Android中一般是用在SD卡的读取和存储上,这和Java中一模一样,不用做其他的解释

(2)对于内置内存的读取,即应用程序的数据文件夹来说,一般使用Android提供的openFileOutput()和 openFileInputStream()方法来获得指定文件的FileInputStream 和 FileOutputStream流 ,得到这些流对象之后就能够使用Java中那一套了

Context提供了如下两个方法来打开本应用程序的数据文件夹里的文件的IO流

 

FileInputStream openFileInputStream(String name):

打开应用程序的数据文件夹下的name文件对应的输入流(/data/data/<Package name>/files/name )

 

FileOutputStream openFileOutputStream(String name , int mode) :

打开应用程序的数据文件夹下的name文件对应的输入流(/data/data/<Package name>/files/name )

 

使用这两个方法,相当于将/data/data/<Package name>/files/目录变成了默认目录,我们只要在方法中的参数中指定文件的名字就行了,不用指定完全路径就能够访问应用程序的数据文件夹

其中的mode参数,指定的是文件的打开方式,还是Context中的静态常量:

Context.MODE_PRIVATE : 该文件只能够被当前的应用程序读写

Context.MODE_APPEND:已追加的方式打开文件

Context.MODE_WORLD_READBLE:该应用程序中的数据能够被其他的程序读

Context.MODE_WORLD_WRITEABLE:该应用程序中的数据能够被其他的程序读、写

 

(3)除此之外、Context还提供了如下几个方法来访问应用程序的数据文件夹

getDir(String name , int mode): 在应用程序的数据文件夹下获取或者创建name对应的子目录

File getFilesDir(): 获取应用程序的数据文件夹的绝对路径

String [ ] fileList():返回该应用程序的数据文件下的全部文件

deleteFile(String ):删除该应用程序的数据文件下的指定文件

5、好了现在将Android中新增的内容全部介绍完了,接下来看介个应用程序实例:

 

【实例应用】


【实例一:数据文件夹下的读写】

android rom存储器 安卓 数据存储器_android

主Activity文件

1 public class MainActivity extends Activity {
 2     
 3     
 4     static final String FILE_NAME = "FileDataStore.bin";
 5     
 6     Button toFileButton ;
 7     Button fromFileButton ;
 8     
 9     EditText toFileText ;
10     EditText fromFileText ;
11 
12     @Override
13     protected void onCreate(Bundle savedInstanceState) {
14         super.onCreate(savedInstanceState);
15         setContentView(R.layout.activity_main);
16         
17         toFileButton = (Button)findViewById(R.id.toFileButton);
18         fromFileButton = (Button)findViewById(R.id.fromFileButton);
19         toFileText = (EditText)findViewById(R.id.toFileText);
20         fromFileText = (EditText)findViewById(R.id.fromFileText);
21         
22         toFileButton.setOnClickListener(new OnClickListener(){
23 
24             @Override
25             public void onClick(View v) {
26                 writeToFile(toFileText.getText().toString());
27                 toFileText.setText("");
28             }
29         });
30         
31         fromFileButton.setOnClickListener(new OnClickListener(){
32 
33             @Override
34             public void onClick(View v) {
35                 fromFileText.setText(readFromFile());
36             }
37         });
38         
39     }
40     
41     
42     public void writeToFile(String content) {
43         FileOutputStream fos;
44         try {
45             
46             fos = openFileOutput(FILE_NAME,MODE_APPEND);
47             BufferedWriter bf  = new BufferedWriter(new OutputStreamWriter(fos));
48             bf.write(content);
49             bf.flush();
50         
51         } catch (FileNotFoundException e) {
52             e.printStackTrace();
53         }catch(IOException e){
54             e.printStackTrace();
55         }
56     }
57     
58     
59     public String readFromFile() {
60         FileInputStream fis;
61         try {
62             char [ ] bufferChars = new char [1024] ;
63             StringBuilder tempBuffer = new StringBuilder("");
64             fis = openFileInput(FILE_NAME);
65             BufferedReader bf  = new BufferedReader(new InputStreamReader(fis));
66             while(bf.read(bufferChars) > 0){
67                  tempBuffer.append(bufferChars);
68             }
69             fis.close();
70             return tempBuffer.toString();
71         } catch (FileNotFoundException e) {
72             e.printStackTrace();
73         }catch(IOException e){
74             e.printStackTrace();
75         }
76         return null ;
77     }
78 }

 

【实例二:SD卡文件夹下的读写】 

首先我们先来介绍一下SD下的文件数据的读写操作

1、当程序通过Context的openFileInput或openFileOutput方法来打开文件的输入流和输出流的时候,程序打开的是应用程序的数据文件夹里的文件,这样存储的文件大小是有限的,因为一般来说,内置存储区相对较小,所以为了存储一些大数据文件,一般选择在SD下进行存储

2、读写SD卡上的文件一般按如下步骤进行:

(1)调用Environment的getExternalStorageState()方法判断手机上面是否插入了SD卡,并且应用程序是否有读写SD卡的权限,使用如下代码:

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

如果符合上述条件的话,就会返回true

(2)调用Environment的getExternalStorageDirector()方法来获得SD卡的目录,也就是 /mnt/sdcard/ , 当然如果你完全可以使用 “/mnt/sdcard/”直接创建文件File对象

(3)之后就是用Java中的那一套流对象来进行文件数据的读取与写入

(4)为了让本应用程序有对SD卡的访问和读写权限,需要在Manifest.xml文件中赋予相关权限:

<!-- 在SD卡中创建和删除文件的权限 -->
 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
 <!-- 向SD卡中写入数据的权限 -->
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

5、了解了上面的内容我们就能够对SD卡文件进行数据的读写了,下面的程序界面和上面的程序一样,只是文件的位置在SD卡中

主Activity文件:

1 import java.io.BufferedReader;
  2 import java.io.File;
  3 import java.io.FileInputStream;
  4 import java.io.IOException;
  5 import java.io.InputStreamReader;
  6 import java.io.RandomAccessFile;
  7 
  8 import android.app.Activity;
  9 import android.os.Bundle;
 10 import android.os.Environment;
 11 import android.view.Menu;
 12 import android.view.MenuItem;
 13 import android.view.View;
 14 import android.view.View.OnClickListener;
 15 import android.widget.Button;
 16 import android.widget.EditText;
 17 
 18 public class MainActivity extends Activity {
 19     
 20     
 21     static final String FILE_NAME = "/FileDataStore.txt";
 22     
 23     Button toFileButton ;
 24     Button fromFileButton ;
 25     
 26     EditText toFileText ;
 27     EditText fromFileText ;
 28 
 29     @Override
 30     protected void onCreate(Bundle savedInstanceState) {
 31         super.onCreate(savedInstanceState);
 32         setContentView(R.layout.activity_main);
 33         
 34         toFileButton = (Button)findViewById(R.id.toFileButton);
 35         fromFileButton = (Button)findViewById(R.id.fromFileButton);
 36         toFileText = (EditText)findViewById(R.id.toFileText);
 37         fromFileText = (EditText)findViewById(R.id.fromFileText);
 38         
 39         toFileButton.setOnClickListener(new OnClickListener(){
 40 
 41             @Override
 42             public void onClick(View v) {
 43                 writeToFile(toFileText.getText().toString());
 44                 toFileText.setText("");
 45             }
 46         });
 47         
 48         fromFileButton.setOnClickListener(new OnClickListener(){
 49 
 50             @Override
 51             public void onClick(View v) {
 52                 fromFileText.setText(readFromFile());
 53             }
 54         });
 55         
 56     }
 57     
 58     
 59     public void writeToFile(String content)  {
 60         try {
 61                     //判定手机中是否插入了SD卡,并且本应用程序有读取权限
 62                     if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
 63                         //获取SD卡的目录
 64                         File sdCardDir = Environment.getExternalStorageDirectory() ;
 65                         File targetFile;
 66                         
 67                         targetFile = new File(sdCardDir.getCanonicalFile()+FILE_NAME);
 68                         
 69                         //已指定的文件创建RandomAccessFile对象
 70                         RandomAccessFile raf = new RandomAccessFile(targetFile , "rw");
 71                         //将文件当前指针移动到内容的末尾
 72                         raf.seek(targetFile.length());
 73                         //将内容写到文件中
 74                         raf.write(content.getBytes());
 75                         raf.close();
 76                     }
 77              } catch (IOException e) {
 78                  e.printStackTrace();
 79         }
 80     }
 81     
 82     
 83     
 84     public String readFromFile() {
 85         try{
 86                     //判定手机中是否插入了SD卡,并且本应用程序有读取权限
 87                     if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
 88                         File sdCardDir = Environment.getExternalStorageDirectory() ;
 89                         FileInputStream fis = new FileInputStream(sdCardDir.getCanonicalPath()+FILE_NAME);
 90                         BufferedReader br = new BufferedReader(new InputStreamReader(fis));
 91                         StringBuilder contentBuffered = new StringBuilder("");
 92                         String tempLines = "";
 93                         while((tempLines = br.readLine()) != null){
 94                             contentBuffered.append(tempLines);
 95                         }
 96                         br.close();
 97                         return contentBuffered.toString();
 98                     }
 99             }catch(IOException e){
100                 e.printStackTrace();
101             }
102         return null ;
103     }
104 }

最后记得在Manifest.xml文件中赋予相关权限

【实例三:SD卡文件浏览器】

 效果如下:(文件夹和文件的图标不一样,最上面的路径如果占不下的话会有省略号,当我们点击下面的“返回”按钮时,文件目录就会返回到上一级)

android rom存储器 安卓 数据存储器_android rom存储器_02

主布局文件activity_main.xml

1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     tools:context="com.penglee.sdfilesexplorer.MainActivity" >
 6 
 7     <TextView
 8         android:id="@+id/filesPath"
 9         android:layout_width="match_parent"
10         android:layout_height="wrap_content"
11         android:textColor="#FF999999"
12         android:paddingTop="10dp"
13         android:ellipsize="middle"
14         android:singleLine="true"/>
15 
16     <ListView
17         android:id="@+id/filesList"
18         android:layout_width="match_parent"
19         android:layout_height="wrap_content"
20         android:layout_below="@id/filesPath"
21         android:paddingTop="10dp" 
22         android:paddingBottom="50dp">
23     </ListView>
24 
25     <Button 
26         android:id="@+id/home"
27         android:layout_width="40dp"
28         android:layout_height="40dp"
29         android:background="@drawable/home"
30         android:layout_alignParentBottom="true"
31         android:layout_centerHorizontal="true"/>
32 </RelativeLayout>

主Activity文件MainActivity.java 文件

1 package com.penglee.sdfilesexplorer;
  2 
  3 import java.io.File;
  4 import java.io.IOException;
  5 import java.util.ArrayList;
  6 import java.util.HashMap;
  7 import java.util.List;
  8 import java.util.Map;
  9 
 10 import android.app.Activity;
 11 import android.os.Bundle;
 12 import android.view.View;
 13 import android.view.View.OnClickListener;
 14 import android.widget.AdapterView;
 15 import android.widget.AdapterView.OnItemClickListener;
 16 import android.widget.Button;
 17 import android.widget.ListView;
 18 import android.widget.SimpleAdapter;
 19 import android.widget.TextView;
 20 import android.widget.Toast;
 21 
 22 public class MainActivity extends Activity {
 23     
 24     Button home ;   //返回上一级的按钮
 25     ListView filesList ; //显示文件的ListView
 26     TextView filesPath ; // 最上面的显示文件路径的TextView
 27     
 28     File currentParent = null ; //当前ListView显示的文件的父文件夹 
 29     File[ ] currentFiles = null ; //当前ListView应该显示的文件集合
 30 
 31     @Override
 32     protected void onCreate(Bundle savedInstanceState) {
 33         super.onCreate(savedInstanceState);
 34         setContentView(R.layout.activity_main);
 35         
 36         home = (Button)findViewById(R.id.home);
 37         filesList = (ListView)findViewById(R.id.filesList);
 38         filesPath = (TextView)findViewById(R.id.filesPath);
 39         
 40         File root  = new File("/mnt/sdcard/") ;
 41         //如果sdcard目录存在
 42         if(root.exists()){
 43             currentParent = root ;
 44             currentFiles = root.listFiles();
 45         }
 46         
 47         //更新当前的ListView视图
 48         upDateListView(currentFiles) ;
 49         
 50         //为ListView注册监听器
 51         filesList.setOnItemClickListener(new OnItemClickListener(){
 52 
 53             @Override
 54             public void onItemClick(AdapterView<?> parent, View view,
 55                     int position, long id) {
 56                 
 57                 //假如单击的Item对应的文件为不是文件夹,就直接返回
 58                 if(currentFiles[position].isFile()) return ;
 59                 
 60                 //如果单击的选项对应的是一个文件夹
 61                 File [ ] temp = currentFiles[position].listFiles();
 62                 if(temp == null){
 63                     Toast.makeText(MainActivity.this, "当前文件夹下的文件不可访问", Toast.LENGTH_SHORT)
 64                                 .show();
 65                 }
 66                 else{
 67                         currentParent = currentFiles[position];
 68                         currentFiles = temp;
 69                         upDateListView(currentFiles) ;
 70                 }
 71             }
 72         });
 73         
 74         //为返回上一级的按钮添加事件监听
 75         home.setOnClickListener(new OnClickListener(){
 76 
 77             @Override
 78             public void onClick(View v) {
 79                 
 80                 try {
 81                     if(! currentParent.getCanonicalPath().equals("/mnt")){
 82                     
 83                             currentParent = currentParent.getParentFile() ;
 84                             currentFiles = currentParent.listFiles();
 85                             upDateListView(currentFiles) ;
 86                     }
 87                 } catch (IOException e) {
 88                     e.printStackTrace();
 89                 }
 90             }
 91         });
 92     }
 93 
 94     private void upDateListView(File [ ] files ){
 95         
 96         //创建一个存储数据的List集合
 97         List<Map<String , Object>> listItems = new ArrayList<Map<String , Object>>( ) ;
 98         
 99         for(int i =0 ; i<files.length ; i++){
100             Map<String , Object> listItem = new HashMap<String , Object>() ;
101             
102             //根据文件和文件夹的不同,加载不同的图标
103             if(files[i].isFile())
104                 listItem.put("icon", R.drawable.file);
105             else
106                 listItem.put("icon", R.drawable.folder);
107             
108             listItem.put("filename", files[i].getName());
109             
110             listItems.add(listItem);
111         }
112         
113         //创建一个SimpleAdapter
114         SimpleAdapter simpleAdapter = new SimpleAdapter(MainActivity.this
115                 , listItems  , R.layout.item 
116                 ,new String[ ]{"icon","filename"}
117                 ,new int [ ]{R.id.icon , R.id.filename});
118         filesList.setAdapter(simpleAdapter);
119         
120         //更新当前的文件的路径
121         try {
122             filesPath.setText("当前路径为:"+currentParent.getCanonicalPath());
123         } catch (IOException e) {
124             e.printStackTrace();
125         }
126     }
127 }

item.xml文件

1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="wrap_content"
 5     android:orientation="horizontal" >
 6     
 7     <ImageView 
 8         android:id="@+id/icon"
 9         android:layout_width="40dp"
10         android:layout_height="40dp" 
11         android:padding="10dp"/>
12     
13     <TextView 
14         android:id="@+id/filename"
15         android:layout_width="match_parent"
16         android:layout_height="wrap_content"
17         android:gravity="center_vertical"
18         android:textSize="16dp"
19         android:padding="10dp"/>
20 
21 </LinearLayout>

最后要在Manifest.xml为文件中添加权限

<!-- 有读取SD文件的权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

【分析】当我们一直点击返回按钮,就会回到/mnt/目录下,我们来看看这个目录下都有哪些文件:

android rom存储器 安卓 数据存储器_android_03

这个目录下后面四个文件我们是没有访问权限的,至于这些文件是干什么的,以后再介绍