谈三点:保存文件到手机内存和SD卡,文件访问权限,获取手机内存和SD卡容量大小
一,保存文件到手机内存和SD卡
这里引用一个案例,写一个登录界面,选择记住密码时将密码保存在手机内存或者SD卡上。
保存到手机内存:
MainActivity.java
<span style="font-size:14px;">package com.example.login;
import java.util.Map;
import com.example.login.service.LoginService;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final String tag = "MainActivity";
private EditText et_name;
private EditText et_password;
private CheckBox RemenberPassword;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化
et_name = (EditText) findViewById(R.id.et_name);
et_password = (EditText) findViewById(R.id.et_password);
RemenberPassword = (CheckBox) findViewById(R.id.cb_remenberpawd);
}
/**
* 登录
*/
@SuppressLint("ShowToast")
public void login(View view) {
String name = et_name.getText().toString().trim();
String password = et_password.getText().toString();
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password)) {
Toast.makeText(this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show();
} else {
// 判断是否保存用户名密码
if (RemenberPassword.isChecked()) {
// 保存密码
Log.i(tag, "需要保存的用户名和密码。");
boolean result = LoginService.saveUserInfo(this, name, password);
if (result) {
Toast.makeText(this, "保存用户信息成功", Toast.LENGTH_SHORT).show();
}
}
// 登录,发送消息到服务器,服务器验证正确性
if ("123".equals(name) && "4038".equals(password)) {
Toast.makeText(this, "登录成功", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "登录失败", Toast.LENGTH_LONG).show();
}
}
}
}
</span>
LoginService.java
<span style="font-size:14px;">package com.example.login.service;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
/**
* 保存用户名和密码的业务方法
* Context 上下文 就是一个类,提供一些方便的api,
* 可以得到应用程序的环境 环境包名 安装路径 文件的路径 资源的路径 资产的路径
* @author Administrator
*/
public class LoginService {
public static boolean saveUserInfo(Context context, String name,
String password) {
// File file = new File("/data/data/com.example.login/Info.txt");//不够灵活,一旦修改包名路径就无效
// context.getFilesDir();//帮助我们返回一个目录 /data/data/包名/files/
File file = new File(context.getFilesDir(), "Infor.txt");
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write((name + "##" + password).getBytes());
fos.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
</span>
这里我们用到了一个获取目录路径的API——Context,上下文 就是一个类,提供一些方便的api,可以得到应用程序的环境
环境包名 安装路径 文件的路径 资源的路径 资产的路径
1】context.getFileDir 得到目录:/data/data/包名/files/
2】context.getCacheDir 得到目录:/data/data/包名/cache/
3】context.openFileOutput(String name, int mode) :Open a private file associated with this Context's application package for writing. Creates the file if it doesn't already exist. (打开这个Context's的应用程序包写入相关的私人文件。创建文件,如果它不存在。)
Parameters:
name The name of the file to open; can not contain path separators.
mode Operating mode. Use 0 or MODE_PRIVATE
for the default operation, MODE_APPEND
to append to an existing file, MODE_WORLD_READABLE
and MODE_WORLD_WRITEABLE
to control permissions.
Returns: FileOutputStream Resulting output stream.
Throws: FileNotFoundException
其中第三种方法也是写入手机内存的一种操作方式,这种方式可以定义写入文件的权限,而代码中的方式写入的文件权限是默认的,默认的就是private,权限的问题后面会讲到。
保存到SD卡上:
上述代码可以将数据写入SD卡上,就是将目录路径改变。
不过在对SD卡写入时,要注意一个问题:
这里是告诉我们对SD卡写入操作时,要获取权限,需要我们在AndroidManifest.xml文件中添加权限:android.permission.WRITE_EXTERNAL_STORAGE
还有,对SD卡的操作前,要检查SD卡的状态,能否被操作:
Environment.getExternalStorageState() 检测外部存储器的状态,返回String类型的数据
这里需要判断所得的环境状态,在Environment中有很多定义好的状态:
他们的意思分别是:(中英文)
MEDIA_BAD_REMOVAL:不正确卸载状态
getExternalStorageState() returns MEDIA_BAD_REMOVAL
if the media was removed before it was unmounted.
MEDIA_CHECKING:装载且正在磁盘检查状态
getExternalStorageState() returns MEDIA_CHECKING
if the media is present and being disk-checked
MEDIA_MOUNTED:装载可读写状态
getExternalStorageState() returns MEDIA_MOUNTED
if the media is present and mounted at its mount point with read/write access.
MEDIA_MOUNTED_READ_ONLY:装载只可读状态
getExternalStorageState() returns MEDIA_MOUNTED_READ_ONLY
if the media is present and mounted at its mount point with read only access.
MEDIA_NOFS:装载但是不支持文件系统
getExternalStorageState() returns MEDIA_NOFS
if the media is present but is blank or is using an unsupported filesystem
MEDIA_REMOVED:卸载状态
getExternalStorageState() returns MEDIA_REMOVED
if the media is not present.
MEDIA_SHARED:卸载并且通过USB存储共享
getExternalStorageState() returns MEDIA_SHARED
if the media is present not mounted, and shared via USB mass storage.
MEDIA_UNMOUNTABLE:如果媒体是存在的,但不能被安装。通常这种情况发生,如果在媒体上的文件系统
被破坏。
getExternalStorageState() returns MEDIA_UNMOUNTABLE
if the media is present but cannot be mounted. Typically this happens if the file system on
the media is corrupted.
MEDIA_UNMOUNTED:没有正确安装状态,未安装好
getExternalStorageState() returns MEDIA_UNMOUNTED
if the media is present but not mounted.
在对SD卡写入的操作中,路径问题也同对手机内存写入操作一样,有定义好的API让我们获取路径,不用写固定路径:
Environment.getExternalStorageDirectory() 获取外部存储设备路径目录
所以应该是这样的:
需要注意的是,这里只是介绍对手机内存和SD卡的写入操作,而案例中的用户名,密码保存方式不能用这种方式,应为作为分隔符的“##”可能与密码弄混,这样安全性就大大减少,并且容易出现bug。所以在用户名,密码一类的配置信息写出一般用SharedPreferences方法,关于这个方法的具体说明,我将在下一篇笔记中讲解。
文件访问权限:
这里在cmd中挂在android的Linux环境,进行一些操作:
这里通过chmod 命令可以更改文件的属性权限。
这里的Infor.txt文件就是写入手机内存时用的上面文件输入输出流方式,权限是默认的,就是private。
而下面的四个文件:ReadWrite.txt、private.txt、read.txt、write.txt都是用context.openFileOutput(String name, int mode) 方法写入的,代码如下:
MainActivity.java
package com.example.login;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Toast;
import com.example.login.service.LoginService;
public class MainActivity extends Activity {
private static final String tag = "MainActivity";
private EditText et_name;
private EditText et_password;
private CheckBox RemenberPassword;
private RadioGroup rg_mode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化
et_name = (EditText) findViewById(R.id.et_name);
et_password = (EditText) findViewById(R.id.et_password);
RemenberPassword = (CheckBox) findViewById(R.id.cb_remenberpawd);
rg_mode = (RadioGroup) findViewById(R.id.rg_mode);
}
/**
* 登录
*/
public void login(View view) {
String name = et_name.getText().toString().trim();
String password = et_password.getText().toString();
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password)) {
Toast.makeText(this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show();
} else {
// 判断是否保存用户名密码
if (RemenberPassword.isChecked()) {
// 保存密码
Log.i(tag, "需要保存的用户名和密码。");
int mode = rg_mode.getCheckedRadioButtonId();
int moded = 0 ;
switch (mode) {
case R.id.rb_private:
moded = 1;
break;
case R.id.rb_read:
moded = 2;
break;
case R.id.rb_write:
moded = 3;
break;
case R.id.rb_read_write:
moded = 4;
break;
default:
break;
}
boolean result = LoginService.saveUserInfo(this, name, password, moded);
if (result) {
Toast.makeText(this, "保存用户信息成功", Toast.LENGTH_SHORT).show();
}
}
// 登录,发送消息到服务器,服务器验证正确性
if ("123".equals(name) && "4038".equals(password)) {
Toast.makeText(this, "登录成功", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "登录失败", Toast.LENGTH_LONG).show();
}
}
}
}
LoginService.java
package com.example.login.service;
import java.io.FileOutputStream;
import android.content.Context;
/**
* 保存用户名和密码的业务方法
* Context 上下文 就是一个类,提供一些方便的api,
* 可以得到应用程序的环境 环境包名 安装路径 文件的路径 资源的路径 资产的路径
* @author Administrator
*/
public class LoginService {
public static boolean saveUserInfo(Context context, String name, String password, int moded) {
FileOutputStream fos = null;
try {
switch (moded) {
case 1:
fos = context.openFileOutput("private.txt", Context.MODE_PRIVATE);
break;
case 2:
fos = context.openFileOutput("read.txt", Context.MODE_WORLD_READABLE);
break;
case 3:
fos = context.openFileOutput("write.txt", Context.MODE_WORLD_WRITEABLE);
break;
case 4:
fos = context.openFileOutput("ReadWrite.txt",
Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);
break;
}
fos.write((name + "##" + password).getBytes());
fos.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
界面如下:
获取手机内存和SD卡大小
这里的方法是从android系统源代码中提取的,获取系统信息的很多方法可以从android源代码中学习。这里就是简单介绍获取SD卡容量和手机内存容量的方法,代码如下:
package com.example.readsdsize;
import java.io.File;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.StatFs;
import android.text.format.Formatter;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.read_sd);
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
long availableBlocks = stat.getAvailableBlocks();
long totalSize = blockSize * totalBlocks;
long availSize = blockSize * availableBlocks;
String totalStr = Formatter.formatFileSize(this, totalSize);
String availStr = Formatter.formatFileSize(this, availSize);
tv.setText("外部总内存:" + totalStr + "\n" + "外部可用内存:" + availStr+ "\n"+ getRomSpaceInfo());
}
public String getRomSpaceInfo() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
long availableBlocks = stat.getAvailableBlocks();
long totalSize = blockSize * totalBlocks;
long availSize = blockSize * availableBlocks;
String totalStr = Formatter.formatFileSize(this, totalSize);
String availStr = Formatter.formatFileSize(this, availSize);
return "内部总内存:" + totalStr + "\n" + "内部可用内存:" + availStr;
}
}