上节学习了如何在手机内部存储中读写文件,本节学习如何在手机的外部存储中读写文件。那就是如何在Sdcard中读写文件。
那我们还是用以前登录界面的例子举例说明,(登录界面请看上节Android 存储学习之在内部存储中读写文件)
先我们显示写的代码:
当点击确定并且自动登录的钩是选中的,则就会在sdcard文件夹写创建一个info.txt文件
代码语言:javascript复制public void login(View v)
{
String name = ed_nam.getText().toString();
String passwd = ed_passwd.getText().toString();
//判断用户名或者密码是否输入
if((name.equals("")) || (passwd.equals("")))
{
Toast.makeText(this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show();
}
else
{
//如果选中自动登录,我们就需要保存用户名和密码
if(cb.isChecked())
{
//创建一个文件,用户保存用户名和密码
File file = new File("sdcard/info.txt");
try {
FileOutputStream fos = new FileOutputStream(file);
//写入用户名和密码,以name##passwd的格式写入
fos.write((name "##" passwd).getBytes());
//关闭输出流
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
}
}
}
执行后,显示效果如下:
同理读也就是将上节读取的路径改为sdcard的路径即可:
代码语言:javascript复制public void readInfo()
{
File file = new File("sdcard/info.txt");
//如果文件存在,则读取
if(file.exists())
{
try {
FileInputStream fin = new FileInputStream(file);
//把字节流转化为字符流
BufferedReader buffer = new BufferedReader(new InputStreamReader(fin));
//读取文件中的用户名和密码
String text = buffer.readLine();
//以##为关键字分割字符
String s[] = text.split("##");
//设置进EditText
ed_nam.setText(s[0]);
ed_passwd.setText(s[1]);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
当然了,同理可知到。我们上面那些写Sdcard的路径是不对的,程序的健壮性不是很高,那就的用Google提供的访问sdcard的API:getExternalStorageDirectory
代码语言:javascript复制 //创建一个文件,用户保存用户名和密码
//File file = new File("sdcard/info.txt");
File file = new File(Environment.getExternalStorageDirectory(), "info.txt");
设想一种情况,当我们往sdcard中写一个文件,但是由于sdcard容量有限,不足与放下此文件,所以在用户打算放入一个文件到sdcard中时,需要先判断存储空间是不满足,不满足请用户给予提醒即可。
那如何获得sdcard的当前可用容量:
代码语言:javascript复制//用户判断是否文件大小超过sdcard的容量
public Boolean sdcardAvailable(int size)
{
File file = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(file.getPath());
//每个块的大小
long blockSize = stat.getBlockSize();
//公共分为多少个块
long totalBlocks = stat.getBlockCount();
//共有多少可用的空间,单位为字节
long availableBlocks = stat.getAvailableBlocks();
if(availableBlocks > size)
{
return true;
}
return false;
}
当写入一个文件时,先和sdcard的可用空间比较即可:
代码语言:javascript复制try {
FileOutputStream fos = new FileOutputStream(file);
//写入用户名和密码,以name##passwd的格式写入
//要写入的数据长度,单位是字节
int len = (name "##" passwd).getBytes().length/8;
if(sdcardAvailable(len))
{
fos.write((name "##" passwd).getBytes());
}
else {
Toast.makeText(this, "sdcard存储空间不足", Toast.LENGTH_SHORT).show();
}
//关闭输出流
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
这样就能避免文件过大,写到一半出现容量不足的情况。
再设想一种情况,当我们突然往sdcard中写入内容时,如果sdcard出现某些问题,没有挂载,那也是不能写入东西的。所以,读写之前需要判断sdcard是否正常运行
代码语言:javascript复制if(cb.isChecked())
{
//创建一个文件,用户保存用户名和密码
//File file = new File("sdcard/info.txt");
/* MEDIA_CHECKING: sd卡正在准备
* MEDIA_MOUNTED:sd卡已经挂载,并且正在读写访问
* MEDIA_REMOVED:没有sd卡
* MEDIA_UNKNOWN:不能识别sd卡
* MEDIA_UNMOUNTED:sd卡存在,但没有挂载
* */
if(Environment.getExternalStorageDirectory().equals(Environment.MEDIA_MOUNTED))
{
File file = new File(Environment.getExternalStorageDirectory(), "info2.txt");
try {
FileOutputStream fos = new FileOutputStream(file);
//写入用户名和密码,以name##passwd的格式写入
//要写入的数据长度,单位是字节
int len = (name "##" passwd).getBytes().length/8;
if(sdcardAvailable(len))
{
fos.write((name "##" passwd).getBytes());
}
else {
Toast.makeText(this, "sdcard存储空间不足", Toast.LENGTH_SHORT).show();
}
//关闭输出流
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
}
也就是在读写时,先判断sdcard是否已经正在运行,如果sdcard的状态是ok的。则执行接下来的操作即可