android基础总结-内部存储和外部存储的大局观

2024-01-05 01:38

本文主要是介绍android基础总结-内部存储和外部存储的大局观,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

研究并了解API的方法,才能根本理解内部存储和外部存储的区别。单纯记忆他们的区别,不如学习学习API,作为开发者,莫要本末倒置,android版本年年更新,不变还是API方法名(你大爷还是你大爷),本篇将从API的角度带大家了解有关存储相关的知识。

开胃菜—android的存储题:
1.SharedPreferences和SQLite的数据存储路径,怎么获取,存在什么位置?
2.今年android主流机型支持双卡,小卡的位置支持扩展第二张SD卡,那么,用代码如何区分内置/扩展SD卡的路径?
3.用Environment操作创建的路径文件,会不会污染SD卡?

一android中存储操作的相关类

关于android存储操作,一般就是路径的操作,比如内部存储中文件路径如何创建获取,外部存储的某个文件如何获取等,相关的类有Environment,Context抽象类(包括众多子类,如Application,Activity等)。还有辅助类StatFs,MemoryInfo。下面依次带大家了解官方API的这些类和方法(API的部分过个眼熟,二–<二>有详细总结):

<一>Environment中File的API详解

在android.os包下,Environment类中可用的11个函数及使用细节:

方法名路径/解释
(1)getDataDirectory()返回用户数据目录(返回File): /data
(2)getDownloadCacheDirectory()返回 /cache content 目录(返回File):/cache
(3)getExternalStorageDirectory()返回外部存储根目录,(返回File), /mnt/sdcard 或者/storage/emulated/0等
(4)getExternalStorageState()判断外部存储状态 (返回String),若是外部存储,返回一个mounted的String,对应Environment.MEDIA_MOUNTED常量
(5)getExternalStorageState(File path)判断文件是否是外部存储,同上
(6) getRootDirectory()返回手机系统根目录下的system文件目录(返回File) :/system
(7)isExternalStorageEmulated()判断外部存储设置是否有效(返回boolean),用法:一些apk安装到外部存储,需要先用此方法判断,false则不可安装
(8)isExternalStorageEmulated(File path)判断path设置是否有效(返回boolean), 用法:一些apk安装到外部存储,需要先用此方法判断,false则不可安装
(9)isExternalStorageRemovable()如果存储设备可以被拆除(例如SD卡)返回true,如果存储设备不能物理删除(例如内置sd卡)返回false
(10)isExternalStorageRemovable(File file)如果存储设备可以被拆除(例如SD卡)返回true,如果存储设备不能物理删除(例如内置sd卡)返回false
(11)getExternalStoragePublicDirectory(String type)获取外部存储的公共目录,共有10个(返回File)用法见下边代码

结合代码,用红米pro真机测试,无外置sd卡,查看输出区别:

     //1.返回结果: /dataLog.d(TAG, Environment.getDataDirectory().toString());//2.返回结果: /cacheLog.d(TAG, Environment.getDownloadCacheDirectory().toString());//3.返回结果: /storage/emulated/0 外部存储的根目录Log.d(TAG, Environment.getExternalStorageDirectory().toString());//4.返回结果:mounted,表示是外部存储Log.d(TAG, Environment.getExternalStorageState().toString());//5.返回结果:mounted Log.d(TAG, Environment.getExternalStorageState(new File(Environment.getExternalStorageDirectory(), "demo.png")).toString());//6.返回结果:/systemLog.d(TAG, Environment.getRootDirectory().toString());//7.返回结果:false 表示外部存储不可安装apkLog.d(TAG, Environment.isExternalStorageEmulated() + "");//8.返回结果:false 表示外部存储不可安装apkLog.d(TAG, Environment.isExternalStorageEmulated(new File(Environment.getExternalStorageDirectory(), "demo.png")) + "");//png存不存在不影响结果//9.返回结果:false 表示是内置内存卡Log.d(TAG, Environment.isExternalStorageRemovable() + "");//10.返回结果:false 表示是内置内存卡Log.d(TAG, Environment.isExternalStorageRemovable(new File(Environment.getExternalStorageDirectory(), "demo.png")) + "");/*** 十大公共目录*///11-1.返回结果:storage/emulated/0/MusicLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).toString());//11-2.返回结果:storage/emulated/0/PicturesLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString());//11-3.返回结果:storage/emulated/0/AlarmsLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS).toString());//11-4.返回结果:storage/emulated/0/DCIMLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString());//11-5.返回结果:storage/emulated/0/DocumentsLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString());//11-6.返回结果:storage/emulated/0/DownloadLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());//11-7.返回结果:storage/emulated/0/MoviesLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).toString());//11-8.返回结果:storage/emulated/0/NotificationsLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS).toString());//11-9.返回结果:storage/emulated/0/PodcastsLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PODCASTS).toString());//11-10.返回结果:storage/emulated/0/RingtonesLog.d(TAG, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES).toString());

<二>Context中和File有关的API详解

这里,调用的文件方法,都是和内部存储和外部的私有目录相关,同Environment的调用有很大区别,根据API的使用注释,私有目录通过context.getExteralxxx的几个方法,其路径在外部存储的/storage/emulated/0/Android/data/程序包名/下,所以对应的,调用了私有目录的方法获取路径时,如果目录不存在,会自动创建,而Environoment的操作的外部存储方法,创建出来需要手动删除.

方法名路径/解释
(1) getCacheDir()返回文件系统该应用程序的缓存目录,且是绝对路径 (返回File),app涉及到缓存常用次方法创建
(2) getCodeCacheDir()为存储缓存代码设计的,回文件系统该应用程序的特殊缓存目录,且是绝对路径(返回File)
(3)getDataDir()返回系统文件该应用程序所有存储的私有文件的绝对路径(返回File)
(4)getDatabasePath(String name)返回系统文件上创建的SQLite的绝对路径,使用该方法的前提是已经使用 SQLiteDatabase.openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory)方法创建了SQLite,其中参数就是name (返回File)
(5)getDir(String name, int mode)检索目录,如果没有,就在应用程序下创建一个name的自定义文件(返回File)
(6)getExternalCacheDir()获取外部存储的私有缓存目录,绝对路径(返回File)
(7)getExternalCacheDirs()获取外部存储的私有缓存目录数组,绝对路径(返回File[])
(8)getExternalFilesDir(String type)获取外部存储的私有文件目录,绝对路径(返回File) type见补充
(9)getExternalFilesDirs(String type)获取外部存储的私有文件目录数组,绝对路径(返回File[])
(10)getExternalMediaDirs()获取外部存储的私有的媒体文件目录 (返回File[])
(11)getFileStreamPath(String name)打开应用程序私有目录的文件,前提是先使用 openFileOutput(String name,int mode)方法创建了私有文件 (返回File)
(12)getFilesDir()同上(返回File)
(13)getNoBackupFilesDir()使用同getFilesDir()(返回File)
(14)getObbDir() )返回应用程序上obb文件的绝对路径(返回File)
(15)getObbDirs()返回应用程序上obb文件的绝对路径(返回File[])

(8)的补充:官方文档给的type只有7个,和外部存储的10大公共目录,都是通过Environment.DIRECTORY_xxx调用,而十大公共目录的type有十个,此处缺少的是DIRECTORY_DOWNLOADS,DIRECTORY_DOCUMENT和DIRECTORY_DCIM这三个type,
支持的7个如下:
DIRECTORY_MUSIC,
DIRECTORY_PODCASTS,
DIRECTORY_ALARMS,
DIRECTORY_RINGTONES
DIRECTORY_NOTIFICATIONS,
DIRECTORY_PICTURES,
DIRECTORY_MOVIES.
通过测试缺少的三个的类型,发现也可以在内部存储中创建,所以type的类型同Environment的type,之所以是7个,是功能需求用不到,不过创建缺少的三个文件,不影响使用。

同样结合代码,使用android studio创建demo,包名是com.storage.demo,查看红米pro的打印结果(三星xplay6结果也相同):

  try {//1.返回结果:/data/user/0/com.storage.demo/cacheLog.d(TAG, "getCacheDir()=" + this.getCacheDir().toString());//2.返回结果:/data/user/0/com.storage.demo/code_cacheLog.d(TAG, "getCodeCacheDir()=" + this.getCodeCacheDir().toString());//3.返回结果:没有支持的LEVEL24设备,就不写了//        Log.d(TAG, "getDataDir()=" + this.getDataDir().toString());//4.返回结果:/data/user/0/com.storage.demo/databases/sjy.dbLog.d(TAG, "getDatabasePath()=" +this.getDatabasePath("sjy.db").toString());//5.返回结果:/data/user/0/com.storage.demo/app_sjy.dbLog.d(TAG, "getDir()=" + this.getDir("sjy.db", MODE_PRIVATE).toString());//6.返回结果:/storage/emulated/0/Android/data/com.storage.demo/cacheLog.d(TAG, "getExternalCacheDir()=" + this.getExternalCacheDir().toString());//7.返回结果:/storage/emulated/0/Android/data/com.storage.demo/cacheFile[] CacheDirs = this.getExternalCacheDirs();StringBuffer CacheDirsbuffer = new StringBuffer();for (int i = 0; i < CacheDirs.length; i++) {CacheDirsbuffer.append(CacheDirs[0].toString());CacheDirsbuffer.append("\n");}Log.d(TAG, "getExternalCacheDirs()=" + CacheDirsbuffer.toString());//8.返回结果: /storage/emulated/0/Android/data/com.storage.demo/files/DCIMLog.d(TAG, this.getExternalFilesDir(Environment.DIRECTORY_DCIM).toString());//9.返回结果:/storage/emulated/0/Android/data/com.storage.demo/files/MoviesFile[] FilesDirs = this.getExternalFilesDirs(DIRECTORY_MOVIES);StringBuffer FilesDirsbuffer = new StringBuffer();for (int i = 0; i < FilesDirs.length; i++) {FilesDirsbuffer.append(FilesDirs[0].toString());FilesDirsbuffer.append("\n");}Log.d(TAG, "getExternalFilesDirs()=" + FilesDirsbuffer.toString());//10.返回结果:/storage/emulated/0/Android/media/com.storage.demoFile[] files = this.getExternalMediaDirs();StringBuffer MediaDirsbuffer = new StringBuffer();for (int i = 0; i < files.length; i++) {MediaDirsbuffer.append(files[0].toString());MediaDirsbuffer.append("\n");}Log.d(TAG, "getExternalMediaDirs()=" + MediaDirsbuffer.toString());//11.返回结果:/data/user/0/com.storage.demo/files/unknown.dbLog.d(TAG, "getFileStreamPath()=" + this.getFileStreamPath("unknown.db").toString());//12.返回结果:/data/user/0/com.storage.demo/filesLog.d(TAG, "getFilesDir()=" + this.getFilesDir().toString());//13.返回结果:/data/user/0/com.storage.demo/no_backupLog.d(TAG, "getNoBackupFilesDir()=" + this.getNoBackupFilesDir().toString());//14.返回结果:/storage/emulated/0/Android/obb/com.storage.demoLog.d(TAG, "getObbDir()=" + this.getObbDir().toString());//15.返回结果:/storage/emulated/0/Android/obb/com.storage.demoFile[] ObbDirs = this.getObbDirs();StringBuffer ObbDirsbuffer = new StringBuffer();for (int i = 0; i < ObbDirs.length; i++) {ObbDirsbuffer.append(ObbDirs[0].toString());ObbDirsbuffer.append("\n");}Log.d(TAG, "getObbDirs()=" + ObbDirsbuffer.toString());} catch (Exception e) {e.printStackTrace();Log.d(TAG, e.toString());}

<三>辅助类ActivityManager.MemoryInfo–RAM空间操作**

如下是MemoryInfo的所有方法:

方法名/变量名详解
(1)availMem系统可用空间RAM大小(返回值 long)
(2)lowMemory当系统环境可用空间很低时,该值设为true(返回值 boolean)
(3)threshold我们认为内存是低的,并且开始杀死后台服务和其他非外部的进程的阈值。(返回值 long)
(4)totalMem内核可访问的总内存。(返回值 long)
describeContents()描述这个可分配实例的集合表示中包含的特殊对象的种类。(返回值 int)
readFromParcel(Parcel source)
writeToParcel(Parcel dest, int flags)把这个物体拉到一个包裹里。

其实Runtime 也有关于JVM(进程)的内存空间操作,这里请看代码打印:
注:测试机红米RAM 3G,xplay6RAM 6G

 private void getRamSpace() {ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();activityManager.getMemoryInfo(memoryInfo);long availableLong = memoryInfo.availMem;long totalLong = memoryInfo.totalMem;//红米pro: RAM可用空间:885M//三星xplay6: RAM可用空间:2953MLog.d(TAG, "RAM可用空间:" + availableLong / 1024 / 1024 + "M");// RAM总空间:2718M//三星xplay6: RAM总空间:5696MLog.d(TAG, "RAM总空间:" + totalLong / 1024 / 1024 + "M");int memory = activityManager.getMemoryClass();float maxMemory = (float) (Runtime.getRuntime().maxMemory() * 1.0 / (1024 * 1024));float totalMemory = (float) (Runtime.getRuntime().totalMemory() * 1.0 / (1024 * 1024));//剩余内存float freeMemory = (float) (Runtime.getRuntime().freeMemory() * 1.0 / (1024 * 1024));//该进程最大分配内存:384M--384.0MLog.d(TAG, "该进程最大分配内存:" + memory + "M" + "--" + maxMemory + "M");//该进程总内存:16.027634MLog.d(TAG, "该进程总内存:" + totalMemory + "M");//该进程剩余内存:4.1224976MLog.d(TAG, "该进程剩余内存:" + freeMemory + "M");}

<四>辅助类StatFs–操作存储空间的API详解

该类向开发者提供了获取空间大小的三种方法,分别是 :
应用可用空间
系统可用空间
系统总空间。
而且每一种空间的获取对应两种计算方法。如下表,API已经按顺序分别介绍:

方法名详解
(1)getBlockSizeLong()系统文件中每一个存储块的大小(返回long) 该值和(2)(3)(4)值分别相乘,获得的结果就是byte值,分别对应(5)(6)(7)的值,见代码打印
(2)getAvailableBlocksLong()应用程序可用存储块的总数(返回long)
(3)getFreeBlocksLong()系统可用存储块的总数(返回long),数值比应用程序的可用存储块总数大 (返回long)(对于普通的应用程序是不可用的)
(4)getBlockCountLong()文件系统上的所有存储块的总数(返回long)
(5) getAvailableBytes()应用程序可用空间字节数(返回long) ,操作1024,可以获得M,G的剩余空间大小(1)*(2)
(6)getFreeBytes()文件系统上空闲的字节数(对于普通的应用程序是不可用的) (1)*(3)
(7)getTotalBytes()系统总字节数 对应(1)*(4)

结合代码的打印,加深理解(注:64G内置存储,无扩展SD卡):

//经测试,StatFs参数不管用context还是Environment,结果没影响StatFs statFs = new StatFs(this.getExternalCacheDir().getPath());long blockSize = statFs.getBlockSizeLong();long availableBlocksLongs = statFs.getAvailableBlocksLong();long freeBlocksLong = statFs.getFreeBlocksLong();long BlocksLong = statFs.getBlockCountLong();//1.返回值:每一个存储块的大小尺寸: 4096Log.d(TAG, "每一个存储块的大小尺寸:" + blockSize);//2.返回值:该app外部存储可用的存储块总数:5148216Log.d(TAG, "该app外部存储可用的存储块总数:" + availableBlocksLongs);//3.返回值:剩余外部存储可用的存储块总数:5185080Log.d(TAG, "剩余外部存储可用的存储块总数:" + freeBlocksLong);//4.返回值: 外部存储总的存储块数量:14059344Log.d(TAG, "外部存储总的存储块数量" + BlocksLong);//5-1.返回值:外部存储应用程序可用空间=20110MLog.d(TAG, "外部存储app可用空间=" + statFs.getAvailableBytes() / 1024 / 1024 + "M");//5-2.返回值:外部存储应用程序可用空间=20110MLog.d(TAG, "外部存储app可用空间=" + blockSize * availableBlocksLongs / 1024 / 1024 + "M");//6-1.返回值: 外部存储系统可用空间20254MLog.d(TAG, "外部存储系统可用空间" + statFs.getFreeBytes() / 1024 / 1024 + "M");//6-2.返回值: 外部存储系统可用空间20254MLog.d(TAG, "外部存储系统可用空间" + blockSize*freeBlocksLong/ 1024 / 1024 + "M");//7-1.返回值: 外部存储总空间53GLog.d(TAG, "外部存储总空间" + statFs.getTotalBytes() / 1024 / 1024 / 1024 + "G");//7-2.返回值: 外部存储总空间53GLog.d(TAG, "外部存储总空间" + blockSize*BlocksLong/ 1024 / 1024 / 1024 + "G");

是不是看完此处,就可以写出一个工具类了呢!!!,那么,问题来了,小米标榜的64G,为什么存储总空间只有53G呢?看下面就知道了

二 开发者进阶总结

<一>ROM和RAM,内部存储和外部存储,他们的区别与联系

首先普及一下硬件的知识,现在的手机,已经更倾向于内置SD卡、内置电池的一体智能机。早年的1G+4G+TF到现在的6G+128G的普配。再用RAM和ROM的定义强加给6G+128G已经变得很狭隘了,因为现在的厂商已经将ROM集成到所谓的128G当中去了(准确的说,是android4.4以后),所谓的内置SD卡,也不单单是存储卡,请看下图(修改:外置存储器修改为外部存储):

这里写图片描述
开发者常困惑的地方就在内置存储器这一部分,内置存储器被分为两部分,内部存储(ROM)和外部存储,这也是为什么厂商常说的64G 128G的存储,实际使用时候,只有53G,90多G的原因,因为还需要分配给内部存储(ROM)空间,给系统的文件,所有app的安装等使用。

在可见性方面,那就是ROM区不对用户开放(root除外);而内置外部存储对用户开放,就像手机界面中的文件管理,能看到你的私有目录,公共目录,还有n些其他文件,所说的53G就是对外开放空间,11G的空间不对外开放

在维护性方面,(结合图片来看)内部存储和外部存储的私有目录,都不需要用户操作,系统自动维护,当安装和卸载app时,这两处的目录会自动创建和删除,在内部存储中,/data分区,就是所有安装app的数据区,下面细讲。/system分区是放置系统文件,手机在出厂时的所有系统文件基本都是放着这个区,/cache分区是系统文件的缓存目录,和系统的一些操作有关,在外部存储的私有目录中,其路径/storage/emulated/0/Android/data/程序包名/下,根据API,用户可以在此目录中操作和app相关的文件操作,比如缓存大型临时数据,IO读写,下面细讲,还有需要注意的一点,当大型app涉及过多的缓存时,私有目录下的缓存有可能在app中设置缓存按钮被手动清除,或设置中,手动清楚;外部存储的公共目录和自定义目录,用户需要自己维护,当存储满了,就需要删除这里头的一些文件.所谓公共目录就是由getExternalStoragePublicDirectory(type)方法调用,指向的文件路径,现在API中是10个,之前是9个,还有一个自己定义目录,这一块的路径都是在内置外部存储的根目录上创建的,可以归咎于开发者不按常理创建而出的,当使用者将app删除时,创建的文件目录不会跟随删除,用户不清理永远保存在存储上,占用空间。当然知名IT的app都有在自定义目录中创建文件的习惯。

所以开发中,一般不建议在公共目录中创建和app相关的文件目录,也不建议在外部存储中创建自定义目录,,同理,app涉及到缓存和数据存储时,开发者有两处选择,一处是内置外部存储的私有目录,另一处是内部存储目录.但是科技发展使手机性能大幅提升,就导致开发者在内置存储随意创建目录,但是本着同行,讲原则,最好利人利己为好,虽然ROM空间扩展不少,也经不起这么败家,推荐在私有目录设置大型缓存.

<二>内部存储的存储操作总结

这部分常用的操作就是第二个:应用程序的内部存储路径,所以,这一部分可以说全是Context操作
1内部存储路径:/system /cache /data

内部存储路径方法(全是 Environment调用 )
系统文件:/systemEnvironment.getRootDirectory()
缓存文件:/cacheEnvironment.getDownloadCacheDirectory()
用户数据:/dataEnvironment.getDownloadCacheDirectory()

2应用程序的内部存储路径:/data/user/0/包名/xxx
常用的方法:

应用程序的内部存储路径方法(全是Context调用)
内部缓存:/data/user/0/com.storage.demo/cachethis.getCacheDir()
SQLite路径:/data/user/0/com.storage.demo/databases/sjy.dbthis.getDatabasePath(“sjy.db”)
自定义内部存储文件:/data/user/0/com.storage.demo/app_sjy.dbthis.getDir(“sjy.db”, MODE_PRIVATE
自定义内部存储的file下文件:/data/user/0/com.storage.demo/files/unknown.dbthis.getFileStreamPath(“unknown.db”)
内部存储的file路径:/data/user/0/com.storage.demo/filesthis.getFilesDir()

SharedPreferences的存储,也在该路径下,通过root,可以查看其路径:/data/user/0/com.storage.demo/shared_prefs/各种xxx.xml文件,SharedPreferences只是interface类型,其具体操作由getSharedPreferences(name,type)获取实现类SharedPreferencesImpl,这部分也只是对数据对xml的操作,没有涉及到路径,所以不用特意关心路径的获取方法。
通常,SharedPreferences的存储会被制作成工具类,但是写法很简单:

SharedPreferences sp = getSharedPreferences(name, type);
Editor et = sp.edit();
et.putXXX(key,value);
et.commit();

<三>外部存储的存储操作总结

外部存储,除了私有目录是Context操作之外,全是用Environment操作
1十大公共目录:

路径方法
storage/emulated/0/XXXEnvironment.getExternalStoragePublicDirectory(type)

2常用私有目录

路径方法(全是Context操作)
缓存目录:/storage/emulated/0/Android/data/com.storage.demo/cachethis.getExternalCacheDir()
缓存目录数组:/storage/emulated/0/Android/data/com.storage.demo/cachethis.getExternalCacheDirs()
IO文件目录7个:/storage/emulated/0/Android/data/com.storage.demo/files/XXXthis.getExternalFilesDir(type)
IO文件目录数组7个/storage/emulated/0/Android/data/com.storage.demo/files/XXXthis.getExternalFilesDirs(type)

3常用自定义目录

路径方法(全是Environment操作)
根路径 :/storage/emulated/0Environment.getExternalStorageDirectory()

这一块就是创建开发者经常操作的方法,操作这里的方法,创建的文件,会污染外部存储,创建的文件不会随app删除而自动删除。
常见的自定义文件,结合File使用,如下:

  String basePath = Environment.getExternalStorageDirectory().getAbsolutePath();File file = new File(basePath, "AAAA/BBB");if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {Log.d(TAG, "进入内置外部存储操作");if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}}

输出自然是右图:这里写图片描述

如何正确使用私有目录

上边的方法可以看到,外部存储创建很方便,一个Environment.getExternalStorageState()就可以。但是,私有目录创建需要Context,这个Context,既可以是Activity的this,也可以是Application的getApplication(),也可以是getContext()等等,是不是有点懵~~,是不是有种context的OOM的担忧?那就对了,要怎么创建呢?分析怎么不OOM,最简单的方法就是在Application中一次性创建:使用Application的Context最安全,能够全局调用。
创建一个FileUtils:

/*** 缓存文件demo*/public class FSFileUtils {public static String basePath = null;// 保存的根目录public static String savePicPath = null;//图片路径public static String saveVoicePath = null;//音频路径public static String registFilePath = null;//注册文件路径(assets下的.lic .model文件路径)/*** application中需要初始化*/public static void initSavePath(Context context) {String path;//文件根路径在 私有目录中File dataFile = context.getApplicationContext().getExternalFilesDir(null);if (dataFile != null) {path = dataFile.getAbsolutePath();} else {//正常的手机,这一部分是永远不会执行 这里是内部存储的路径,dataFile = context.getApplicationContext().getFilesDir();path = dataFile.getAbsolutePath();}basePath = path;savePicPath = basePath + File.separator + Constants.PIC_FILE;saveVoicePath = basePath + File.separator + Constants.VOICE_FILE;registFilePath = path;mkDir(registFilePath);mkDir(savePicPath);mkDir(saveVoicePath);}/*** 创建路径*/public static boolean mkDir(String dirPath) {boolean isExist;File dirFile = new File(dirPath);if (!dirFile.exists() || !dirFile.isDirectory()) {isExist = dirFile.mkdir();} else {isExist = true;}return isExist;}/*** 清除缓存*/public static void clearFiles() {File baseFile = new File(basePath);File[] fileList;if (baseFile.exists() && baseFile.isDirectory()) {fileList = baseFile.listFiles();for (int i = 0; i < fileList.length; i++) {if (fileList[i].isFile()) {fileList[i].delete();fileList[i].exists();}}}}}

给文件在Application的onCreate中初始化:

 @Overridepublic void onCreate() {super.onCreate();//其他操作//初始化缓存路径FSFileUtils.initSavePath(getApplicationContext());}

最后,就是在任意地方调用FSFileUtils .xxx路径。

<四>被忽略的扩展SD卡操作

扩展内存就是我们插入的外置SD卡,google在底层实现上,更倾向使用内置的外部存储,其底层获取扩展卡路径的方法System.getenv(“SECONDARY_STORAGE”)的SECONDARY_STORAGE,在API level23之后就过时了。还有一种反射方法,代码如下:

 /*** 获取扩展sd卡跟路径** @param mContext* @return*/private static String getExtendedMemoryPath(Context mContext) {StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);Class<?> storageVolumeClazz = null;try {storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");Method getPath = storageVolumeClazz.getMethod("getPath");Method isRemovable = storageVolumeClazz.getMethod("isRemovable");Object result = getVolumeList.invoke(mStorageManager);final int length = Array.getLength(result);for (int i = 0; i < length; i++) {Object storageVolumeElement = Array.get(result, i);String path = (String) getPath.invoke(storageVolumeElement);boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);if (removable) {return path;}}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return "没有扩展sd卡";}

通过反射的方式使用在sdk中被 隐藏 的类 StroageVolume 中的方法getVolumeList(),获取所有的存储空间(Stroage Volume),然后通过参数is_removable控制,来获取内部存储和外部存储(内外sd卡)的路径,参数 is_removable为false时得到的是内置sd卡路径,为true则为外置sd卡路径。

这部分不做多介绍,正常开发,内置外部存储足够使用,所以不建议再使用扩展卡,google也是这么推荐的。

结语:此处只简单介绍了API方法和其具体使用含义,底层逻辑实现并未讲解,但疏通了存储硬件和代码操作的关系,知其然更要知其所以然,真正的存储开发,还涉及更多操作,这只是皮毛,愿小伙伴们自得其乐!

github示例 点击跳转

android开发 开篇总结,多多关照

这篇关于android基础总结-内部存储和外部存储的大局观的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/571251

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

二分最大匹配总结

HDU 2444  黑白染色 ,二分图判定 const int maxn = 208 ;vector<int> g[maxn] ;int n ;bool vis[maxn] ;int match[maxn] ;;int color[maxn] ;int setcolor(int u , int c){color[u] = c ;for(vector<int>::iter