所有Android设备都支持可以保存文件的共享外部存储器,这个外部存储器可以是可移动存储器(如SD卡),也可以是内置在设备中的外部存储器(不可移动)。外部存储器上的文件时全部可读的,当设备通过USB连接电脑和电脑互传文件时,外部存储器上的文件不可修改。
当外部存储器被挂载到电脑上或被移除,文件对android设备就不可见了,且此时外部存储器上的文件是没有安全保障的。所有程序都可以读写外部存储器上的文件,用户也可以删除这些文件。
在模拟器中使用SDCard,你需要先创建一张SDCard卡(当然不是真的SDCard,只是镜像文件)。创建SDCard可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令进行创建,如下:在Dos窗口中进入androidSDK安装路径的tools目录,输入以下命令创建一张容量为2G的SDCard,文件后缀可以随便取,建议使用.img:
mksdcard 2048M D:\AndroidTool\sdcard.img
警告:里面的这些外部文件是会消失不可见的——如果用户把外部存储器挂在到一台电脑上或移除该媒介(SD卡),同时你储存在外部储存器上的文件没有强制的安全保证。
所有应用程式都可以读写这些文件并且用户也可以删除它们。
如果不希望创建的文件在应用卸载后被删除,可以使用下面的方法,因为目录和文件不会随着应用程序的卸载而被删除;
目录和文件位于外部存储(SD卡)的根目录中:Musics/、Pictures/、Movies/等;
API8及以上:
getExternalStoragePublicDirectory(String type),打开一个外部存储目录,参数type指定子目录类型(DIRECTORY_MUSIC、DIRECTORY_PICTURES等);
public class Environment {
public static StringDIRECTORY_MUSIC = "Music"; //音频文件
public static StringDIRECTORY_PODCASTS = "Podcasts"; //广播
public static StringDIRECTORY_RINGTONES = "Ringtones"; //铃声
public static StringDIRECTORY_ALARMS = "Alarms"; //警报
public static StringDIRECTORY_NOTIFICATIONS = "Notifications"; //通知
public static StringDIRECTORY_PICTURES = "Pictures"; //图片
public static StringDIRECTORY_MOVIES = "Movies"; //电影
public static StringDIRECTORY_DOWNLOADS = "Download"; //下载
public static StringDIRECTORY_DCIM = "DCIM"; //照片
//...不完整的Environment类内容
}
API7及以下:
getExternalStorageDirectory(),返回外部存储的根目录的File对象。然后将文件存储在:
Music/- 媒体扫描仪划分为用户的音乐在这里发现的所有媒体。
Podcasts/- 媒体扫描仪的分类在这里找到一个podcast的所有媒体。
Ringtones/ - 媒体扫描器分类作为铃声,在这里发现所有的媒体。
Alarms/- 媒体扫描仪发出报警声,这里发现的所有媒体分类。
Notifications/- 媒体扫描仪的分类作为通知的声音在这里发现的所有媒体。
Pictures/- 所有照片(不包括那些用相机拍摄)。
Movies/- 所有电影(不包括用摄像机拍摄的)。
Download/- 杂项下载。
应用程序被卸载,目录和内容随之被卸载;
目录结构:/Android/data/
API8及以上:
getExternalStoragePublicDirectory(String type),打开一个外部存储目录,参数type指定子目录类型(DIRECTORY_MUSIC、DIRECTORY_PICTURES等,Null则为根目录);
API7及以下:
getExternalStorageDirectory(),打开外部存储的根目录:
应用程序被卸载,缓存内容随之被删除;
缓存文件应该被妥善管理,以节约存储空间;
目录结构:/Android/data/
API8及以上:getExternalCacheDir()打开缓存文件夹;
API7及以下:getExternalStorageDirectory()打开外部存储的根目录,然后需手动按照目录结构写入缓存文件。
boolean mExternalStorageAvailable =false;
boolean mExternalStorageWriteable =false;
String state =Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
mExternalStorageAvailable = mExternalStorageWriteable = true;
} else
if(Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
{
// We can only read the media
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
// Something else is wrong. It may be one of many other states, but allwe need
// to know is we can neither readnor write
mExternalStorageAvailable = mExternalStorageWriteable = false;
}
以上代码检测外部存储器是否可用于读和写。你可能希望检测getExternalStorageState()函数返回的其他状态,例如媒介是否被共享了(连接到了电脑)、是否完全遗失了、被意外移除了等等。当你的应用需要访问媒介的时候,你可以使用这些(携带更多的信息)来提示用户。
(私有)访问外部存储器上的文件 (Accessing files on externalstorage)
如果你使用的是APILevel 8或更高版本,使用getExternalFilesDir()函数来打开一个代表外部存储器目录(你最终储存文件的地方)的File对象。该函数使用一个type参数来指定你希望的子目录的类型,例如DIRECTORY_MUSIC和DIRECTORY_RINGTONES (传null 值,会返回你应用文件目录的根目录)。该函数会在需要时创建合适的目录。
如果你使用的是APILevel 7或更低的版本,使用getExternalStorageDirectory()函数来打开一个代表外部存储器根目录的File对象。然后,你应该将你的数据写入到以下的目录:
/Android/data/
从Media Scanner中隐藏你的文件:
包含一个命名为 .nomedia的空文件到你的外部文件目录(注意文件名中的点前缀)。这样会防止Android的media scanner通过读取你的媒介文件并包含他们到应用中,像画廊或音乐。
(公有)保存可被共享的文件 (Saving files that should beshared)
如果你希望保存的文件并不特定于你的应用并且不会在应用卸载时被删除,请将他们保存到外部存储器上的一个公有目录。这些目录放置在外部存储器的根目录下,比如 Music/ , Pictures/ , Ringtones/ 及其他。
在APILevel 8或更高版本中,使用 getExternalStoragePublicDirectory() 函数,传给它一个你希望的公有目录类型,比如 DIRECTORY_MUSIC , DIRECTORY_PICTURES, DIRECTORY_RINGTONES或其他。该函数将在必要的时候创建合适的目录。
如果你使用的是APILevel 7或更低的版本,使用getExternalStorageDirectory()函数来打开一个代表外部存储器根目录的File对象。然后,储存你的共享文件到以下目录中的一个里面.
(私有)保存缓存文件 (Saving cache files)
如果你使用的是APILevel 8或更高的版本,使用getExternalCacheDir()函数来打开一个代表外部存储器中你将储存缓存文件的目录的File对象。如果用户卸载你的应用,这些文件将会被自动删除。无论如何,在你应用的生命中,你应该管理这些缓存文件并在不再需要的时候移除它们以便保存文件空间。
如果你使用的是APILevel 7或更低的版本,使用getExternalStorageDirectory()函数来打开一个代表外部存储器根目录的File对象,然后将你的缓存数据写入到下面的目录:/Android/data/
/**
* @Title: SDCardUtils.java
* @Package com.store.utils
* @Description: TODOtodo:
* @author wuzq,[email protected]
* @date 2012-4-6 下午3:28:08
* @version V1.0
**/
package com.store.utils;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;
import com.store.activity.R;
/**
* 项目名称:DataStoreDemo
* 类名称:SDCardUtils
* 类描述:
* 创建人:wuzq,[email protected]
* 创建时间:2012-4-6 下午3:28:08
* 修改人:wuzq,[email protected]
* 修改时间:2012-4-6 下午3:28:08
* 修改备注:
* @version
**/
public class SDCardUtils {
private Context mContext;
private BroadcastReceiver mExternalStorageReceiver;
private boolean mExternalStorageAvailable = false;
private boolean mExternalStorageWriteable = false;
private static final int ERROR = -1;
public SDCardUtils(Context context){
this.mContext = context;
}
/**
*
* @Title: updateExternalStorageState
* @Description:更新外部存储卡(SD)的状态
*/
public void updateExternalStorageState() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// SD卡可读写
mExternalStorageAvailable = mExternalStorageWriteable = true;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// SD卡只读
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
// SD卡不可读不可写
mExternalStorageAvailable = mExternalStorageWriteable = false;
}
}
/**
*
* @Title: startWatchingExternalStorage
* @Description:开始监听SD卡
*/
public void startWatchingExternalStorage() {
mExternalStorageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("test", "Storage: " + intent.getData());
updateExternalStorageState();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addAction(Intent.ACTION_MEDIA_REMOVED);
mContext.registerReceiver(mExternalStorageReceiver, filter);
updateExternalStorageState();
}
/**
*
* @Title: stopWatchingExternalStorage
* @Description:停止监听SD卡
*/
public void stopWatchingExternalStorage() {
mContext.unregisterReceiver(mExternalStorageReceiver);
}
/**
* 将Bitmap对象转化为字节数组
* @param bitmap
* @return
*/
public byte[] Bitmap2Bytes(Bitmap bitmap){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
return baos.toByteArray();
}
/**
*
* @Title: isExternalStorageAvailable
* @Description: 检测external Storage是否可读写
* @return external Storage可读写返回true,否则返回false
*/
public static boolean isExternalStorageAvailable() {
boolean state = false;
String extStorageState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
state = true;
}
return state;
}
/**
*
* @Title: isExternalStorageAvailable
* @Description: 检测external Storage是否可读
* @return external Storage可读返回true,否则返回false
*/
public static boolean isExternalStorageReadOnly() {
boolean state = false;
String extStorageState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
state = true;
}
return state;
}
/**
* @Title:writeToExternalStoragePublic
* @Description:存储文件到SD卡的公共目录
* @param filename - the filename to write to
* @param content - the content to write
*/
public void writeToExternalStoragePublic(String filename, byte[] content) {
// API Level 7 or lower, use getExternalStorageDirectory()
// to open a File that represents the root of the external storage, but
// writing to root is not recommended, and instead app should write to
// app-specific directory, as shown below.
String packageName = mContext.getPackageName();
String path = "/Android/data/" + packageName + "/files/";
if (isExternalStorageAvailable() && !isExternalStorageReadOnly()) {
try {
//File root = Environment.getExternalStorageDirectory();
//File file = new File(root, filename); // avoid writing to root
File file = new File(path, filename); // instead write /Android/data...
file.mkdirs();
FileOutputStream fos = new FileOutputStream(file);
fos.write(content);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* readExternallStoragePublic
* @Description:读取SD卡公共目录中的文件内容
* @param: filename - the filename to read to
* @param: content - the file contents
*/
public byte[] readExternallStoragePublic(String filename) {
int len = 1024;
byte[] buffer = new byte[len];
String packageName = mContext.getPackageName();
String path = "/Android/data/" + packageName + "/files/";
if (!isExternalStorageReadOnly()) {//?
try {
File file = new File(path, filename); // instead write /Android/data...
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int nrb = fis.read(buffer, 0, len); // read up to len bytes
while (nrb != -1) {
baos.write(buffer, 0, nrb);
nrb = fis.read(buffer, 0, len);
}
buffer = baos.toByteArray();
fis.close();
} catch (FileNotFoundException e) {
Log.d(mContext.getString(R.string.app_name)+".readInternalStorage()",
"FileNotFoundException: " + e);
e.printStackTrace();
} catch (IOException e) {
Log.d(mContext.getString(R.string.app_name)+".readInternalStorage()",
"IOException: " + e);
e.printStackTrace();
}
}
return buffer;
}
/**
*
* @Title: deleteExternalStoragePublicFile
* @Description:删除外部存储公共目录下的文件
* @param filename 要删除的文件名
*/
void deleteExternalStoragePublicFile(String filename) {
String packageName = mContext.getPackageName();
String path = "/Android/data/" + packageName + "/files/"+filename;
File file = new File(path, filename); // instead write /Android/data...
if (file != null) {
file.delete();
}
}
/**
* @Title:writeToExternalStoragePublic
* @Description:存储文件到应用程序的私有目录files下.API8及其以上可用
* @param filename - the filename to write to
* @param content - the content to write
*/
public void writeToExternalStoragePrivate_API8(String filename, byte[] content) {
if (!isExternalStorageReadOnly()) {
try {
File file = new File(mContext.getExternalFilesDir(null), filename);
FileOutputStream fos = new FileOutputStream(file);
fos.write(content);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*
* @Title: readExternallStoragePrivate_API8
* @Description:从应用程序的私有目录files中读取文件。API8及其以上可用
* @param filename 要读取的文件名
* @return 文件内容
*/
public byte[] readExternallStoragePrivate_API8(String filename) {
int len = 1024;
byte[] buffer = new byte[len];
if (!isExternalStorageReadOnly()) {
try {
File file = new File(mContext.getExternalFilesDir(null), filename);
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int nrb = fis.read(buffer, 0, len); // read up to len bytes
while (nrb != -1) {
baos.write(buffer, 0, nrb);
nrb = fis.read(buffer, 0, len);
}
buffer = baos.toByteArray();
fis.close();
} catch (FileNotFoundException e) {
Log.d(mContext.getString(R.string.app_name)+".readInternalStorage()",
"FileNotFoundException: " + e);
e.printStackTrace();
} catch (IOException e) {
Log.d(mContext.getString(R.string.app_name)+".readInternalStorage()",
"IOException: " + e);
e.printStackTrace();
}
}
return buffer;
}
/**
*
* @Title: deleteExternalStoragePrivateFile_API8
* @Description:删除应用程序私有目录files下的文件。API8及其以上可用
* @param filename 要删除的文件名
*/
void deleteExternalStoragePrivateFile_API8(String filename) {
File file = new File(mContext.getExternalFilesDir(null), filename);
if (file != null) {
file.delete();
}
}
/**
*
* @Title: saveExternalStoragePrivatePicture
* @Description:保存图片到应用程序的私有目录Pictures下
* @param filename 图片文件名
* @param bitmap 要保存的图片
*/
public void saveExternalStoragePrivatePicture(String filename,Bitmap bitmap){
if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){
try {
File path = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File file = new File(path, filename);
// Make sure the Pictures directory exists.
if(!path.exists()){
path.mkdirs();
}
/*OutputStream os = new FileOutputStream(file);
os.write(Bitmap2Bytes(bitmap));
os.close();*/
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*
* @Title: saveExternalStoragePrivatePicture
* @Description:保存图片到应用程序的私有目录Pictures下
* @param filename 图片文件名
* @param bitmap 要保存的图片文件流
*/
public void saveExternalStoragePrivatePicture(String filename,InputStream bitmapStream){
if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){
try {
File path = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File file = new File(path, filename);
// Make sure the Pictures directory exists.
if(!path.exists()){
path.mkdirs();
}
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[bitmapStream.available()];
bitmapStream.read(data);
os.write(data);
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*
* @Title: getExternalStoragePrivatePicture
* @Description:读取应用程序私有目录Pictures下的图片
* @param filename 要读取的文件名
* @return
*/
public Bitmap getExternalStoragePrivatePicture(String filename){
Bitmap bitmap = null;
if(isExternalStorageAvailable() || isExternalStorageReadOnly()){
File path = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File file = new File(path, filename);
if(file.exists()){
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
}
}
return bitmap;
}
/**
*
* @Title: deleteExternalStoragePrivatePicture
* @Description:删除应用程序私有目录Pictures下的图片
* @param filename 要删除的图片文件名
*/
public void deleteExternalStoragePrivatePicture(String filename) {
if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){
File path = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File file = new File(path, filename);
if(file.exists()){
file.delete();
}
}
}
/**
*
* @Title: hasExternalStoragePrivatePicture
* @Description:判断应用程序私有目录Pictures下是否存在某图片
* @param filename 图片文件名
* @return
*/
public boolean hasExternalStoragePrivatePicture(String filename) {
if(isExternalStorageAvailable() && !isExternalStorageReadOnly()){
File path = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File file = new File(path, filename);
return file.exists();
}
return false;
}
//////////////////////////////////////////////////////////////////////////
// Get External Cache Directory //////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/**
* Helper method to retrieve the absolute path to the application specific
* external cache directory on the filesystem. These files will be ones that
* get deleted when the app is uninstalled or when the device runs low on
* storage. There is no guarantee when these files will be deleted.
*
* Note: This uses a Level 8+ API.
*
* @return the the absolute path to the application specific cache directory
*/
public String getExternalCacheDirectory() {
String extCacheDirPath = null;
File cacheDir = mContext.getExternalCacheDir();
if (cacheDir != null) {
extCacheDirPath = cacheDir.getPath();
}
return extCacheDirPath;
}
/**
* Get contents of named asset
* @param name the name of the asset
*/
public byte[] getAsset(String name) {
byte[] buffer = null;
try {
AssetManager mngr = mContext.getAssets();
InputStream is = mngr.open(name);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
buffer = new byte[1024*3];
is.read(buffer);
bo.write(buffer);
bo.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}
/**
*
* @Title: getAvailableInternalMemorySize
* @Description:获取内容卡可用容量
* @return
*/
public static long getAvailableInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
/**
*
* @Title: getTotalInternalMemorySize
* @Description:获取内存卡总容量
* @return
*/
public static long getTotalInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
/**
*
* @Title: getAvailableExternalMemorySize
* @Description:获取SD卡可用容量
* @return
*/
public static long getAvailableExternalMemorySize() {
if (isExternalStorageAvailable()) {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
// 获取Block的Size
long blockSize = stat.getBlockSize();
// 获取空闲Block数量
long availableBlocks = stat.getAvailableBlocks();
// return availableBlocks * blockSize;//返回bit大小值
// return (availableBlocks * blockSize)/1024; //KIB单位
return (availableBlocks * blockSize) / 1024 / 1024;// MIB单位
} else {
return ERROR;
}
}
/**
*
* @Title: getTotalExternalMemorySize
* @Description:获取SD卡总容量
* @return
*/
public static long getTotalExternalMemorySize() {
if (isExternalStorageAvailable()) {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
// 块数量
long totalBlocks = stat.getBlockCount();
// return totalBlocks * blockSize;
// return (totalBlocks * blockSize)/1024;//KIB单位
return (totalBlocks * blockSize) / 1024 / 1024;// MIB单位
} else {
return ERROR;
}
}
}