一:手机内部存储空间文件的读取;
1.使用该种方式存储文件,首先要获取本应用程序的数据文件夹,android为我们提供了openFileOutput(String name,int mode)和openFileInput(String name)来获取。查看帮助文档可见
其中openFileOutput(String name,int mode)的返回类型为FileOutputStream,即使用该方法创建一个文件输出流,用来向文件中写入数据。其中第一个参数String为文件名,第二个int型参数mode有以下四个值:
Context.MODE_PRIVATE: 默认模式,表示私有数据;
Context.MODE_APPEND: 检查文件是否存在,如果存在会往文件追加内容,否则创建文件再写入;
Context.MODE_WORLD_READABLE: 当前文件可以被其他应用读取;
Context.MODE_WORLD_WRITEABLE: 当前文件可以被其他文件写入。
以上四个值,除了MODE_APPEND会将内容追加到文件末尾,其他的都会覆盖掉原文件内容。如果需要使用多个值可以这样使用:Context.MODE_PRIVATE+Context.MODE_APPEND;
openFileInput(String name)的返回类型为FileInputStream,即使用该方法创建一个文件输入流,用来读取数据。其中参数String为需要读取的文件名,FileOutputStream和FileInputStream为java API中IO包里面的一个类,其中有这样一段注释:
也就是说这个类用于处理字节流的文件有较好的性能,却也不是不可以用来处理字符,下面是用该类中的方法来处理字符的代码:
方法一:
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
save=(TextView)findViewById(R.id.save);
open=(TextView)findViewById(R.id.open);
edit=(EditText)findViewById(R.id.edit);
edit2=(EditText)findViewById(R.id.edit2);
save.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
write(edit.getText().toString());
edit.setText("");
Toast.makeText(getApplicationContext(), "写入成功!", Toast.LENGTH_SHORT).show();
}
});
open.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
edit2.setText(read());
}
});
}
public void write(String content){ //传入String
FileOutputStream output;
try {
output = openFileOutput("aaa",Context.MODE_WORLD_READABLE); //用可读模式创建文件
byte[] by=content.getBytes(); //因为FileOutputStream用来处理字节,所以要将传入的String转换为字节型
output.write(by); //向文件里面写入数据
output.flush(); //刷新文件流
output.close(); //关闭流释放资源
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String read(){
FileInputStream input = null;
String str ="";
try {
input = openFileInput("aaa"); //从指定文件获得字节
/*使用下边注释中的代码时无法完整读取数据
*还会有乱码现象发生
*估计是读取过程中发生了阻塞*/
//int lenth=input.toString().length(); //因为在使用read方法时需要指定字节的长度,所以我们提前获取数据的长度
//byte[] by=new byte[lenth]; //字节大小为数据的长度
int lenth=input.available(); //该方法专门用来处理上述问题
input.read(lenth); //和上面write方法一样,用来处理字节
str=new String(by,"UTF-8"); //因为最终给文本设置的类型为string型,所以我们还需要通过utf-8编码将by转换为字符型
input.close(); //关闭流释放内存
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str; //该返回的str即转型后的by
}
以上操作结果可以在设备内存date/date/包名/file/文件夹中查看,若是真机调试,必须要有root权限。
前文中已经提到过FileOutputStream和FileInputStream用于处理字节,所以如果要较好地处理字符数据就得要将字节转换为字符类型,正好java api提供为我们提供了InputStreamReader和OutputStreamWriter用于处理该类问题,查看api可见:
代码如下:
方法二:
public void write(String content){ //传入String
try {
FileOutputStream output = openFileOutput("aaa",Context.MODE_WORLD_READABLE); //用可读模式创建文件(字节流)
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(output,"UTF-8")); //该处先将字符数据添加缓存功能后再存入字节流
writer.write(content); //写入数据
writer.flush();
writer.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String read(){
String str ="";
try {
String string=null;
FileInputStream input = openFileInput("aaa"); //从指定文件获得字节
BufferedReader buffer=new BufferedReader(new InputStreamReader(input,"UTF-8")); //将字节流转换为字符流并为其添加缓存功能
while((string=buffer.readLine())!=null){ //判断读取数据是否为空,若不判断程序就无法处理,会报错闪退
String ch=buffer.readLine(); //或许readLine是该类中最有用的一个方法,事实证明确实如此
str=new String(ch);
buffer.close();
}
}catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str; //该返回的str即转型后的by
}
上述方法是将字节流和字符流互相转换后进行数据读取,并为其添加了缓存功能,当然如果不用缓存功能也可以,将它们进行转换后直接进行读取。另外,java API中还为我们提供了一些方法可以达到类似效果,我们可以使用字节缓冲类BufferedOutputStream和BufferedInputStream实现缓冲功能,具体功能,api注释可见:
根据本人理解,缓存功能其实是先将数据装进一个数组,然后每次对数组内的数据进行修改,直到最后确定保存时才将数据写入文件,避免了对内存文件的频繁调用,以下为实现代码:
方法三:
public void write(String content){ //传入String
try {
FileOutputStream output = openFileOutput("aaa",Context.MODE_WORLD_READABLE);
BufferedOutputStream buffer=new BufferedOutputStream(output); //为其实现缓冲功能
byte[] by=content.getBytes();
buffer.write(by); //write返回类型为void
buffer.flush();
buffer.close();
}catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String read(){
String str = null;
try {
FileInputStream input = openFileInput("aaa");
BufferedInputStream buffer=new BufferedInputStream(input);
byte[] by=new byte[buffer.available()];
input.read(by); //参考api可见read返回类型为int,所以要获取字节长度
str=new String(by);
input.close();
}catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str; //该返回的str即转型后的by
}
其实我刚开始的想法是用API提供的FileReader和FileWriter中的方法来进行对手机内部存储文件的读取,或许有很多朋友和我这种想法一样。后来我试了很多次都无法实现这种效果,总结原因如下:
1.android提供用来获取设备存储目录的方法为openFileOutput(String name,int mode)和openFileInput(String name),然而这两种方法的返回值是用来处理字节的文件流,分别为FileOutputStream和FileInputStream。FileReader和FileWriter为处理字符的文件流;
2.常用的存储方式是关于字节的处理;
二:sd卡中文件的读取:
原理和方式与设备内存文件的读取基本一样,只不过先要判断sd卡的状态,具体步骤与代码如下:
public void write(String content){ //传入String
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ //判断sd卡状态
File file=Environment.getExternalStorageDirectory(); //得到sd卡根目录
File date=new File(file,"date"); //创建文件
try {
BufferedWriter writer =new BufferedWriter(new FileWriter(date)); //为字符流添加缓存
writer.write(content); //写入数据
writer.flush();
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public String read(){
String str="";
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
try {
File file=Environment.getExternalStorageDirectory();
File date=new File(file,"date");
BufferedReader reader=new BufferedReader(new FileReader(date)); //作用同上
String string=null;
while((string=reader.readLine())!=null){ //判断数据是否为空,如果不加判断,程序会报错闪退
str=new String(reader.readLine()); //读取每行数据,它的返回值为string类型
reader.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return str; //该返回的str即转型后的by
}