当程序通过Context的openFileInput或openFileOutput来打开文件输入流、输出流时,程序所打开的都是应用程序的数据文件夹里的文件(即手机内置的存储空间)。为了更好地存、取应用程序的打文件数据,应用程序需要读、写SD卡上的文件。
转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空)
一、读、写SD卡上的文件开发思路
1.调用Environment的getExternalStorageState()方法判断手机是否插入了SD卡,并却应用程序具有读写SD卡的权限;
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
注释:如果手机已插入SD卡,且应用程序具有读写SD卡的能力,则返回为true.
2.获取SD卡的根目录。调用Environment的getExternalStorageDirectory()方法来获取外部存储器(SD卡)的根目录
File sdCardDir=Environment.getExternalStorageDirectory();
3.使用FileInputStream、FileOutputStream(以字节为单位);FileReader或FileWriter(以字符为单位)读、写SD卡里的文件
读文件数据举例:
File sdCardDir=Environment.getExternalStorageDirectory();
FileInputStream fis=new FileInputStream(sdCardDir.getCanonicalPath()+FILE_NAME);
BufferedReader br=new BufferedReader(new InputStreamReader(fis)); //将指定输入流包装成BufferedReader
StringBuilder sb=new StringBuilder("");
String line=null;
while((line=br.readLine())!=null)
{
sb.append(line);
}
br.close();
return sb.toString();
写数据到文件举例:
File sdCardDir=Environment.getExternalStorageDirectory();
File targetFile=new File(sdCardDir.getCanonicalPath()+"testfile.txt"); //在指定路径下实例化一个File对象
RandomAccessFile raf=new RandomAccessFile(targetFile,"rw"); //以指定文件创建RandomAccessFile对象,向SD卡指定文件追加内容(targetFile为一个文件对象)
raf.seek(targetFile.length()); //将文件记录指针移动到最后
raf.write(content.getBytes());
raf.close();
4.在应用程序的清单文件(AndroidManifest.xml)中添加读、写SD卡的权限
<!-- 在SD卡中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 向SD卡写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
5.实例源码
实现:在SD卡路径/mnt/sdcard/目录下创建一个testfile.txt文件(不存在时自动创建),向该文件读、写数据。
package com.example.android.sdcard_2;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import android.os.Bundle;
import android.os.Environment;
public class MainActivity extends ActionBarActivity {
final String FILE_NAME="/testfile.txt";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//获取组件:两个按钮、两个文本
Button write=(Button)findViewById(R.id.writeButton);
Button read=(Button)findViewById(R.id.readButton);
final EditText edit2=(EditText)findViewById(R.id.writetext);
final EditText edit1=(EditText)findViewById(R.id.readtext);
//1.写数据到SD卡文件中
write.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
write(edit2.getText().toString()); //获取文本框中的数据并写到SD卡的文件中
edit2.setText(""); //清空文本框
}
});
//2.为读取SD卡按钮绑定事件监听器
read.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
edit1.setText(read()); //读取SD卡文件数据到文本框中
}
});
}
//3.成员函数:实现写SD卡模块,如果手机插入了SD卡,而且应用程序具有访问SD的权限
private void write(String content) {
try{
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))//判断手机是否插入SD卡
{
//a.获取SD卡的目录
File sdCardDir=Environment.getExternalStorageDirectory(); //获取SD卡的目录
File targetFile=new File(sdCardDir.getCanonicalPath()+FILE_NAME); //在指定路径下实例化一个File对象
//b.以指定文件创建RandomAccessFile对象,向SD卡指定文件追加内容(targetFile为一个文件对象)
RandomAccessFile raf=new RandomAccessFile(targetFile,"rw");
//c.将文件记录指针移动到最后
raf.seek(targetFile.length());
//d.输出文件内容并关闭RandomAccessFile
raf.write(content.getBytes());
raf.close();
}
else
{
Toast.makeText(this, "手机没有插入SD卡,请插入SD卡再试试", Toast.LENGTH_SHORT).show();
}
}catch(IOException e){
e.printStackTrace();
}
}
//3.成员函数:读SD卡,如果手机插入了SD卡,而且应用程序具有访问SD的权限
private String read() {
try{
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
//a.获取SD卡的目录
File sdCardDir=Environment.getExternalStorageDirectory();
//b.获取指定文件对应的输入流
FileInputStream fis=new FileInputStream(sdCardDir.getCanonicalPath()+FILE_NAME);
//c.将指定输入流包装成BufferedReader
BufferedReader br=new BufferedReader(new InputStreamReader(fis));
StringBuilder sb=new StringBuilder("");
//c.循环读取文件内容
String line=null;
while((line=br.readLine())!=null)
{
sb.append(line);
}
//d.关闭资源并返回读取到的内容
br.close();
return sb.toString();
}
else
{
Toast.makeText(this, "手机没有插入SD卡,请插入SD卡再试试", Toast.LENGTH_SHORT).show();
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
注释1:RandomAccessFile向SD卡指定文件追加内容--如果使用FIleOutputStream向指定文件写入数据,FileOutputStream会把原有的文件内容清空,那就不是追加文件内容了。
效果演示:
二、实战:SD卡文件浏览器
实现功能:当程序启动时,系统启动获取/mnt/sdcard目录下的全部文件。文件夹,并使用ListView将它们显示出来;当用户单击ListView指定的列表项时,系统将会显示该列表项下全部文件夹和内容。
1.界面布局文件\res\layout\main.xml
<?xml version="1.0" encoding="utf-8" ?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- 显示当前路径的文本框 -->
<TextView
android:id="@+id/path"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_alignParentTop="true" />
<!-- 列表当前路径下所有文件的ListView -->
<ListView
android:id="@+id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="#000"
android:dividerHeight="1px"
android:layout_below="@id/path"/>
<!-- 返回上一级目录的按钮 -->
<Button
android:id="@+id/parent"
android:layout_width="50dp"
android:layout_height="34dp"
android:background="@drawable/home"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
2.主程序\src\包名\SDFileExplorer.java:利用File的ListFile列出指定目录的全部文件
package com.example.android_sdcard_1;
/*SD卡文件浏览器*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
//应用出现NullPointerException
public class MianActivity extends Activity {
ListView listView=null;
TextView textView=null;
File currentParent=null; //记录当前的父文件夹
File[] currentFiles; //记录当前路径下的所有文件的文件数组
/*1.onCreate成员函数*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mian);
listView=(ListView)findViewById(R.id.list);//获取列出全部文件的ListView
textView=(TextView)findViewById(R.id.path);
//a.获取系统的SD卡的目录
File root=new File("/mnt/sdcard");
//b.判断SD卡是否存在,如果存在获取指定文件夹下的所有文件并填充到ListView中
if(root.exists())
{
currentParent=root; //记录当前的父文件夹为/mnt/sdcard
currentFiles=root.listFiles(); //将当/mnt/sdcard路径下的所有文件存放到数组currentFiles中
inflateListView(currentFiles); //使用当前目录下的全部文件、文件夹来填充listView组件中
//c.为ListView的列表项的单击事件绑定监听器
listView.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//用户单击了文件,直接返回,不做任何处理
if(currentFiles[position].isFile()) return;
//获取用户点击的文件夹的所有文件,不是文件夹或者文件夹目录下无文件返回错误提示
File[] tmp=currentFiles[position].listFiles(); //列出子文件夹下的所有文件或目录并保存到tmp数组中
if(tmp==null || tmp.length == 0)
{
Toast.makeText(MianActivity.this, "提示信息:当前路径不可访问或者该路径下没有文件", Toast.LENGTH_SHORT).show();
}
else
{
//1.获取用户单击的列表项对应的文件夹,设为当前的父文件夹
currentParent=currentFiles[position];
//2.保存当前的父文件夹内的全部文件和文件夹
currentFiles=tmp;
//3.再次更新listView中的数据
inflateListView(currentFiles);
}
}
});
//d.获取上一级目录的按钮,并为按钮设置监听器
Button parent=(Button)findViewById(R.id.parent);
parent.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
try{
if(!currentParent.getCanonicalFile().equals("/mnt/sdcard"))
{
//1.获取上一级目录
currentParent=currentParent.getParentFile();
//2.列出当前目录下所有文件
currentFiles=currentParent.listFiles();
//3.再次更新ListView
inflateListView(currentFiles);
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
});
}
}
/*2.inflateListView成员函数-更新列表组件内容*/
private void inflateListView(File[] files) {
//a.创建一个List集合,List集合的元素是Map
List<Map<String,Object>> listItems=new ArrayList<Map<String,Object>>();
//b.依次将文件夹下所有的文件或文件夹名称存放到List集合中
for(int i=1;i<files.length;i++)
{
Map<String,Object> listItem=new HashMap<String,Object>(); //创建一个Map实例,所有数据使用哈希表组织排序
if(files[i].isDirectory()) //如果当前File是文件夹,使用folder图标;否者使用file图标
{
listItem.put("icon", R.drawable.folders);
}
else
{
listItem.put("icon", R.drawable.file);
}
listItem.put("filename", files[i].getName()); //将返回的文件名映射到filename键中
listItems.add(listItem); //将一个列表项添加到List集合中
}
//c.创建一个SimpleAdapter,实现数据到listview组件的映射
SimpleAdapter simpleAdapter=new SimpleAdapter(this
,listItems
,R.layout.line
,new String[]{"icon", "fileName"}
,new int[]{R.id.icon,R.id.file_name});
//d.为ListView设置Adapter
listView.setAdapter(simpleAdapter);
try{
textView.setText("当前路径为:"+currentParent.getCanonicalPath());
}catch(IOException e)
{
e.printStackTrace();
}
}
}
3.列表视图资源文件\res\layout\line.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/file_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000000"/>"
</LinearLayout>