在安卓的开发中,有时候要用到大文件的存储,这个时候就不能存储在应用内部(data/data),只能借助外部存储。而外部存储又分为手机机身的存储空间(一级sd卡)和外置sd卡存储空间(二级sd卡)。
1.要存储首先是获得读写权限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />//操作文件 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />//向sd卡写入 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />//读取sd卡信息
2.接下来是获得外存储路径
我们一般会想到用Environment.getExternalStorageDirectory().getAbsolutePath(),但是由于国内手机系统各种定制,各个厂
商都做过了修改。Environment.getExternalStorageDirectory().getAbsolutePath()的意思是获得外部存储的路径,各个厂商自己认为的外部存储可能不一样,所以这个方法能调用到的路劲可能也有所差别。
怎么解决呢?安卓源代码里面有一个类专门管理外部存储,那就是StorageManager。调用storageManager.getStorageVolumes()就能获得所有外置sd卡的挂载情况。但是这个方法要7.0或者以上才能调用。所以我们考虑使用反射。public static ArrayList<StorageInfo> getAvaliableStorages(Context context) { ArrayList<StorageInfo> storagges = new ArrayList<>(); StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); try { Class<?>[] paramClasses = {}; Method getVolumeList = StorageManager.class.getMethod("getVolumeList", paramClasses); getVolumeList.setAccessible(true); Object[] params = {}; Object[] invokes = (Object[]) getVolumeList.invoke(storageManager, params); if (invokes != null) { StorageInfo info = null; for (int i = 0; i < invokes.length; i++) { Object obj = invokes[i]; Method getPath = obj.getClass().getMethod("getPath", new Class[0]); String path = (String) getPath.invoke(obj, new Object[0]); info = new StorageInfo(path); File file = new File(info.path); if ((file.exists()) && (file.isDirectory()) && (file.canWrite())) { Method isRemovable = obj.getClass().getMethod("isRemovable", new Class[0]); String state = null; try { Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class); state = (String) getVolumeState.invoke(storageManager, info.path); info.state = state; } catch (Exception e) { e.printStackTrace(); } if (info.isMounted()) { info.isRemoveable = ((Boolean) isRemovable.invoke(obj, new Object[0])).booleanValue(); storagges.add(info); } } } } } catch (NoSuchMethodException e1) { e1.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } storagges.trimToSize(); return storagges; }public class StorageInfo { public String path; public String state; public boolean isRemoveable; public StorageInfo(String path) { this.path = path; } public boolean isMounted() { return "mounted".equals(state); } }这样便得到了所有的外置存储卡的信息。我的手机信息是机身存储 /storage/emulated/0/1外置sd卡 /storage/sdcard1/3.文件写入我们只要调用storageInfo.isRemoveable 可移除的就是二级存储卡,一般就是我们可拔插的sd卡。不可移除的就是机身存储。
调用storageInfo.isMounted()就可知道这个存储位置是否可用。
(1)机身存储位置的文件写入
这个没什么好讲,只要获得路径便可直接写入
(2)外置sd卡的文件写入
在4.4以前,外置sd卡也是可以直接写入的,但是在4.4以后Android开始有了多卡存储。于是拓展的sd卡,便没有了写入权限。
据说是为了安卓系统可以在应用卸载之后可以轻松的删掉本地文件。
但是,Android并不是禁止了sd卡所有的写入权限。在特定的目录下,我们还是可以执行写入操作的。那就是在sd卡的Android/data/"+context.getPackageName()+"/files/ 路径下,允许用户写入文件。这就可以理解了,特定的sd卡目录在应用卸载之后会被清除文件,而至于机身自带的存储空间要清除残留文件肯定是没问题的。这样就可以在一定程度上缓解安卓机
越用越卡的毛病了(残留文件都被系统删除了)。所以,如果我们要在外置sd卡写入文件的话,只要写在这个路径下就可以了,我的是/storage/sdcard1/Android/data/"+context.getPackageName()+"/files/需要注意的是,在创建这个路径的时候要先调用context.getExternalFilesDir(null).getAbsolutePath(),一定要先调用这一句否则文件不能写入,这句话大概就是创建固定路径。
context.getExternalFilesDir(null).getAbsolutePath();//要先执行此方法,创建sd卡目录,否则不能创建目录 String direction = "/storage/sdcard1/Android/data/"+context.getPackageName()+"/files/ ";File file = new File(direction); if (!file.exists()){ file.mkdirs(); }大功告成!