您的位置:首页 > 移动开发 > Android开发

Android 读取手机文件夹向指定文件夹下存放

2016-10-10 19:10 232 查看
        昨天项目需要向指定的文件夹下保存图片,需要使用文件管理器去选择指定的文件夹,当然最后由于逻辑太奇葩(不能选择文件夹,只能选择文件夹下的某一个文件)被否定了,改为自己读取手机存储的文件夹,并且可以创建。当中遇到了几个问题记录一下:

      1.手机存储现在由三部分组成了基本上:内部存储、手机内置外部存储(ROM)、手机SD卡

         1)内部存储:

getFilesDir()
这个方法可以的到手机内部的存储(好像是包文件夹下的,我没测试)

        2)手机内置外部存储(Rom):

new File(Environment.getExternalStorageDirectory().getAbsolutePath())
这个方法可以得到文件

       3)SD卡存储 问题来了,上面的方法好像似曾相识,不就是得到Sd卡吗?我也是被困扰了很久,当然也没得到答案,没办法了,通过下面方法得到了:

File file = new File("/storage/sdcard1");
if (null != file.listFiles() && file.listFiles().length > 0) {
fileNameList.add("外置存储");
}


更正:如果用以上方法来判断是否挂在sd卡,以及获取sd卡的根目录,测试中有些手机是不准确的,因为有的手机外置sd卡的根路径不一定是“/storage/sdcard1”,因此找个一个大神的方法,抽取出来他的工具类以及bean类,如下:

        public class StorageUtils {
public static ArrayList<StorageBean> getStorageData(Context pContext) {
final StorageManager storageManager = (StorageManager) pContext.getSystemService(Context.STORAGE_SERVICE);
try {
//得到StorageManager中的getVolumeList()方法的对象
final Method getVolumeList = storageManager.getClass().getMethod("getVolumeList");
//得到StorageVolume类的对象
final Class<?> storageValumeClazz = Class.forName("android.os.storage.StorageVolume");
//获得StorageVolume中的一些方法
final Method getPath = storageValumeClazz.getMethod("getPath");
Method isRemovable = storageValumeClazz.getMethod("isRemovable");

Method mGetState = null;
//getState 方法是在4.4_r1之后的版本加的,之前版本(含4.4_r1)没有
// (http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/os/Environment.java/)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
try {
mGetState = storageValumeClazz.getMethod("getState");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
//调用getVolumeList方法,参数为:“谁”中调用这个方法
final Object invokeVolumeList = getVolumeList.invoke(storageManager);
final int length = Array.getLength(invokeVolumeList);
ArrayList<StorageBean> list = new ArrayList<>();
for (int i = 0; i < length; i++) {
final Object storageValume = Array.get(invokeVolumeList, i);//得到StorageVolume对象
final String path = (String) getPath.invoke(storageValume);
final boolean removable = (Boolean) isRemovable.invoke(storageValume);
String state;
if (mGetState != null) {
state = (String) mGetState.invoke(storageValume);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
state = Environment.getStorageState(new File(path));
} else {
if (removable) {
state = EnvironmentCompat.getStorageState(new File(path));
} else {
//不能移除的存储介质,一直是mounted
state = Environment.MEDIA_MOUNTED;
}
}
}
long totalSize = 0;
long availaleSize = 0;
if (Environment.MEDIA_MOUNTED.equals(state)) {
totalSize = StorageUtils.getTotalSize(path);
availaleSize = StorageUtils.getAvailableSize(path);
}
StorageBean storageBean = new StorageBean();
storageBean.setAvailableSize(availaleSize);
storageBean.setTotalSize(totalSize);
storageBean.setMounted(state);
storageBean.setPath(path);
storageBean.setRemovable(removable);
list.add(storageBean);
}
return list;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}

private static long getTotalSize(String path) {
try {
final StatFs statFs = new StatFs(path);
long blockSize = 0;
long blockCountLong = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
blockSize = statFs.getBlockSizeLong();
blockCountLong = statFs.getBlockCountLong();
} else {
blockSize = statFs.getBlockSize();
blockCountLong = statFs.getBlockCount();
}
return blockSize * blockCountLong;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}

private static long getAvailableSize(String path) {
try {
final StatFs statFs = new StatFs(path);
long blockSize = 0;
long availableBlocks = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
blockSize = statFs.getBlockSizeLong();
availableBlocks = statFs.getAvailableBlocksLong();
} else {
blockSize = statFs.getBlockSize();
availableBlocks = statFs.getAvailableBlocks();
}
return availableBlocks * blockSize;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}

private static final long A_GB = 1073741824;
private static final long A_MB = 1048576;
private static final int A_KB = 1024;

public static String fmtSpace(long space) {
if (space <= 0) {
return "0";
}
double gbValue = (double) space / A_GB;
if (gbValue >= 1) {
return String.format("%.2fGB", gbValue);
} else {
double mbValue = (double) space / A_MB;
if (mbValue >= 1) {
return String.format("%.2fMB", mbValue);
} else {
final double kbValue = space / A_KB;
return String.format("%.2fKB", kbValue);
}
}
}
}
public class StorageBean implements Parcelable {
/**
* 根路径
*/
private String path;
/**
*挂在情况 一种是挂在了 mounted  一种是未挂在 removed
*/
private String mounted;
/**
* 是否可以移除,如果不可移除表示内部存储,可移除代表TF存储(外挂SD卡)
*/
private boolean removable;
/**
* 总共大小
*/
private long totalSize;
/**
* 可用大小
*/
private long availableSize;

public String getPath() {
return path;
}

public void setPath(String path) {
this.path = path;
}

public String getMounted() {
return mounted;
}

public void setMounted(String mounted) {
this.mounted = mounted;
}

public boolean getRemovable() {
return removable;
}

public void setRemovable(boolean removable) {
this.removable = removable;
}

public long getTotalSize() {
return totalSize;
}

public void setTotalSize(long totalSize) {
this.totalSize = totalSize;
}

public long getAvailableSize() {
return availableSize;
}

public void setAvailableSize(long availableSize) {
this.availableSize = availableSize;
}

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.path);
dest.writeString(this.mounted);
dest.writeByte(removable ? (byte) 1 : (byte) 0);
dest.writeLong(this.totalSize);
dest.writeLong(this.availableSize);
}

public StorageBean() {
}
protected StorageBean(Parcel in) {
this.path = in.readString();
this.mounted = in.readString();
this.removable = in.readByte() != 0;
this.totalSize = in.readLong();
this.availableSize = in.readLong();
}

public static final Parcelable.Creator<StorageBean> CREATOR = new Parcelable.Creator<StorageBean>() {
@Override
public StorageBean createFromParcel(Parcel source) {
return new StorageBean(source);
}

@Override
public StorageBean[] newArray(int size) {
return new StorageBean[size];
}
};

@Override
public String toString() {
return "StorageBean{" +
"path='" + path + '\'' +
", mounted='" + mounted + '\'' +
", removable=" + removable +
", totalSize=" + totalSize +
", availableSize=" + availableSize +
'}';
}
}
       以上工具类就可以了,不过发现有的手机读取出来的集合中居然后8个存储位置,当然只要取前两个就可以了(其他的不知道什么鬼)。

       2. Android6.0系统的手机读取不到外置存储下面的文件和文件夹

File[] files = file.listFiles();
这个方法中files为空。什么鬼?后来发现是权限问题,虽然在功能清单文件中申请了权限,但是6.0需要代码中对危险权限进行动态二次申请所以加上如下代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//6.0手机
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {//没有授权权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE},
MY_PERMISSIONS_REQUEST_READ_CONTACTS_SD);
} else {//授权了权限
file = new File("/storage/sdcard1");
nextFileList(file);
}
} else {//6.0以下系统
file = new File("/storage/sdcard1");
nextFileList(file);
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {//手机内置外部存贮
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {//授权同意
file = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
nextFileList(file);
} else {//授权被拒绝

}
}
break;
case MY_PERMISSIONS_REQUEST_READ_CONTACTS_SD://sd卡
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {//授权同意
file = new File("/storage/sdcard1");
nextFileList(file);
} else {//授权被拒绝

}
break;
}
}
当然这里对于用户拒绝了需要再次请求处理我们没有处理,就没有继续研究。

   

        3.显示的文件夹中含有隐藏的文件夹,需要删除掉,这个其实很简单,因为隐藏的文件夹都是以“.”开头的,所以使用如下方法就可以,顺便还有文件夹按照字母排序的方法

for (int num = 0; num < files.length; num++) {
if (files[num].isDirectory()) {
String name = files[num].getName();
if (!name.startsWith(".")) {//排除掉隐藏的文件夹
fileNameList.add(name);
}
}
}
Collections.sort(fileNameList, Collator.getInstance(Locale.ENGLISH));//对文件夹名称排序


最后把整个demo放到我们资源中,有需要的可以下载。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: