今天项目有一个需求,就是将资源语音文件复制到SD卡中,闲的没事瞎搞了一下,做了SD卡辅助工具类,以便以后用到!!!
使用之前,我们先获得SD卡权限问题:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
工具类使用方法在代码里面已经写得详细了,直接看代码就OK了,里面主要包括内容是:
1、判断sd卡是否能用。
2、获取sd卡是否能用。
3、获取系统存储路径。
4、获取系统存储路径。
5、获取sd卡的剩余容量
6、复制文件asset目录的文件到sd卡下
package com.djp.magpietest.test03;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;
import android.util.Log;
/**
* SD卡相关的辅助类
*/
public class SDCardUtils {
private static final String SEPARATOR = File.separator;//路径分隔符
private SDCardUtils() {
throw new UnsupportedOperationException("不能被实例化");
}
/**
* 判断SDCard是否可用
*
* @return
*/
public static boolean isSDCardEnable()
{
return Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED);
}
/**
* 获取SD卡路径
*
* @return
*/
public static String getSDCardPath() {
return Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator;
}
/**
* 获取SD卡的剩余容量 单位byte
*
* @return
*/
public static long getSDCardAllSize() {
if (isSDCardEnable()) {
StatFs stat = new StatFs(getSDCardPath());
// 获取空闲的数据块的数量
long availableBlocks = (long) stat.getAvailableBlocks() - 4;
// 获取单个数据块的大小(byte)
long freeBlocks = stat.getAvailableBlocks();
return freeBlocks * availableBlocks;
}
return 0;
}
/**
* 获取指定路径所在空间的剩余可用容量字节数,单位byte
*
* @param filePath
* @return 容量字节 SDCard可用空间,内部存储可用空间
*/
public static long getFreeBytes(String filePath) {
// 如果是sd卡的下的路径,则获取sd卡可用容量
if (filePath.startsWith(getSDCardPath()))
{
filePath = getSDCardPath();
} else
{// 如果是内部存储的路径,则获取内存存储的可用容量
filePath = Environment.getDataDirectory().getAbsolutePath();
}
StatFs stat = new StatFs(filePath);
long availableBlocks = (long) stat.getAvailableBlocks() - 4;
return stat.getBlockSize() * availableBlocks;
}
/**
* 获取系统存储路径
*
* @return
*/
public static String getRootDirectoryPath() {
return Environment.getRootDirectory().getAbsolutePath();
}
/**
* 判断文件是否已存在
* @param strFile
* @return
*/
public static boolean isFileExist(String strFile) {
try {
File f=new File(strFile);
if(!f.exists())
{
return false;
}
}
catch (Exception e)
{
return false;
}
return true;
}
/**
*
* 方式一
* 复制单个文件到sd卡内存
* @param outPath String 输出文件路径 如:data/user/0/com.test/files
* @param fileName String 要复制的文件名 如:abc.txt
* @return <code>true</code> if and only if the file was copied; <code>false</code> otherwise
*/
public static void copyAssetsSingleFile(Context context,String outPath, String fileName) {
File file = new File(outPath);
if (!file.exists()) {
if (!file.mkdirs()) {
Log.e("this", "copyAssetsSingleFile:不能创建目录");
}
}
try {
InputStream inputStream =context.getResources().getAssets().open(fileName); //输入流 可以把数据从硬盘,读取到Java的虚拟中来,也就是读取到内存中
File outFile = new File(file, fileName);
FileOutputStream fileOutputStream = new FileOutputStream(outFile); //文件输出流 写入到文件中
//将字节从inputStream传输到fileOutputStream
byte[] buffer = new byte[1024];//创建字节数组,其长度设置为1024
int byteRead;
while (-1 != (byteRead = inputStream.read(buffer))) {//以字节流的形式读取文件中的内容
fileOutputStream.write(buffer, 0, byteRead);//写入到转存文件中
}
Log.e("this",fileName+"文件复制完成");
inputStream.close();
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 方式二
* 复制assets中的文件到指定目录
* @param context 上下文
* @param assetsPath assets资源路径
* @param storagePath 目标文件夹的路径
*/
public static void copyFilesFromAssets(Context context, String assetsPath, String storagePath) {
String temp = "";
if (TextUtils.isEmpty(storagePath)) {
return;
} else if (storagePath.endsWith(SEPARATOR)) {
storagePath = storagePath.substring(0, storagePath.length() - 1);
}
if (TextUtils.isEmpty(assetsPath) || assetsPath.equals(SEPARATOR)) {
assetsPath = "";
} else if (assetsPath.endsWith(SEPARATOR)) {
assetsPath = assetsPath.substring(0, assetsPath.length() - 1);
}
AssetManager assetManager = context.getAssets();
try {
File file = new File(storagePath);
if (!file.exists()) {//如果文件夹不存在,则创建新的文件夹
file.mkdirs();
}else {
Log.d("this","该文件已经存在");
}
// 获取assets目录下的所有文件及目录名
String[] fileNames = assetManager.list(assetsPath);
if (fileNames.length > 0) {//如果是目录 apk
for (String fileName : fileNames) {
if (!TextUtils.isEmpty(assetsPath)) {
temp = assetsPath + SEPARATOR + fileName;//补全assets资源路径
}
String[] childFileNames = assetManager.list(temp);
if (!TextUtils.isEmpty(temp) && childFileNames.length > 0) {//判断是文件还是文件夹:如果是文件夹
copyFilesFromAssets(context, temp, storagePath + SEPARATOR + fileName);
} else {//如果是文件
InputStream inputStream = assetManager.open(temp);
readInputStream(storagePath + SEPARATOR + fileName, inputStream);
}
}
} else {//如果是文件 doc_test.txt或者apk/app_test.apk
InputStream inputStream = assetManager.open(assetsPath);
if (assetsPath.contains(SEPARATOR)) {//apk/app_test.apk
assetsPath = assetsPath.substring(assetsPath.lastIndexOf(SEPARATOR), assetsPath.length());
}
readInputStream(storagePath + SEPARATOR + assetsPath, inputStream);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/*** 读取输入流中的数据写入输出流
*
* @param storagePath 目标文件路径
* @param inputStream 输入流
*/
public static void readInputStream(String storagePath, InputStream inputStream) {
File file = new File(storagePath);
try {
if (!file.exists()) {
// 1.建立通道对象
FileOutputStream fos = new FileOutputStream(file);
// 2.定义存储空间
byte[] buffer = new byte[inputStream.available()];
// 3.开始读文件
int lenght = 0;
while ((lenght = inputStream.read(buffer)) != -1) {// 循环从输入流读取buffer字节
// 将Buffer中的数据写到outputStream对象中
fos.write(buffer, 0, lenght);
}
Log.d("this","复制完成文件..................");
fos.flush();// 刷新缓冲区
// 4.关闭流
fos.close();
inputStream.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
调用实现类:
package com.djp.magpietest.test03;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
public static final String TEMP_DIR = Environment.getExternalStorageDirectory() +"/"+"Hello";//转存路径
public static final String OFFLINE_FILE_ONE = "test1.txt";
public static final String OFFLINE_FILE_TWO = "test2.txt";
public static final String OFFLINE_FILE_THIRD = "image/111.png";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//判断sd卡是否能用
if (SDCardUtils.isSDCardEnable()){
// Log.d("tag","sd卡能用");
}else {
// Log.d("tag","sd卡不能用");
}
//获取sd卡路径
String path = SDCardUtils.getSDCardPath();
Log.d("this","sd路径:"+path);
//获取系统存储路径
String path1 = SDCardUtils.getRootDirectoryPath();
// Log.d("tag",path1);
// 获取SD卡的剩余容量 单位byte
String size = String.valueOf(SDCardUtils.getSDCardAllSize());
// Log.d("tag",size);
//initFile();//复制文件到sd卡内存(方式一)
copysd();//复制单个文件到sd卡内存*(方式二)
}
private void initFile(){
Log.i("this", "开始初始化离线文件.............");
String [] files = {OFFLINE_FILE_ONE,OFFLINE_FILE_TWO}; //离线文件数组
if (SDCardUtils.isSDCardEnable()){//判断sd卡是否可用
for (String file : files){ //遍历离线文件
String filePath =TEMP_DIR+"/"+file;//转存路径 /storage/emulated/0/Hello/test.text
if (!SDCardUtils.isFileExist(filePath)){//判断文件是否存在
Log.i("this", "准备复制文件file:"+file+" 到指定目录:"+filePath);
//SDCardUtils.copyFromAssetsToSdcard(MainActivity.this,false,file,TEMP_DIR);//是否覆盖已存在的目标文件
SDCardUtils.copyAssetsSingleFile(MainActivity.this,TEMP_DIR,file);
}else {
Log.d("this", file+"文件存在不需要复制");
}
}
}else {
Log.d("this", "Sd卡不能用!");
return;
}
}
private void copysd() {
Log.d("this","开始初始化离线文件.................");
//SDCardUtils.copyFilesFromAssets(this, OFFLINE_FILE_ONE, TEMP_DIR);
SDCardUtils.copyFilesFromAssets(this,OFFLINE_FILE_THIRD,TEMP_DIR);
}
}
由于本人安卓知识及技术有限,代码如有错误或不足请评论指出,非常感谢!