【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中新增的内容全部介绍完了,接下来看介个应用程序实例:
【实例应用】
【实例一:数据文件夹下的读写】
主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卡文件浏览器】
效果如下:(文件夹和文件的图标不一样,最上面的路径如果占不下的话会有省略号,当我们点击下面的“返回”按钮时,文件目录就会返回到上一级)
主布局文件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/目录下,我们来看看这个目录下都有哪些文件:
这个目录下后面四个文件我们是没有访问权限的,至于这些文件是干什么的,以后再介绍