Android 存储体系:内部存储、SD 卡、U 盘挂载读写、工控文件持久化方案

发布时间:2026/9/22 17:36:42

Android 存储体系:内部存储、SD 卡、U 盘挂载读写、工控文件持久化方案
Android 存储体系内部存储、SD 卡、U 盘挂载读写、工控文件持久化方案工控设备的数据比女朋友还难伺候——丢了不行、路径搞错也不行、U盘没挂载就写更不行。今天就把Android存储体系给你从头捋到脚。一、Android 存储架构总览Android的存储体系可以简化成三大块存储类型路径特征是否需要权限典型用途内部存储/data/data/包名/不需要应用私有数据、数据库外部存储内部SD/storage/emulated/0/Android 10需要共享文件、日志导出可移动存储外部SD/U盘/storage/XXXX-XXXX/需要SAF或StorageManager数据备份、固件升级小提示很多人被外部存储这个名字坑了。外部存储不是指SD卡——手机自带的那个32GB/128GB存储空间在Android眼里就是外部存储External Storage它是焊接在主板上的、根本拔不掉的。真正的SD卡叫可移动存储Removable Storage。一张图理解它们的关系Android 文件系统 ├── 内部存储 (无需权限) │ ├── /data/data/com.example.industrial/ │ │ ├── files/ ← getFilesDir() │ │ ├── databases/ ← SQLite数据库 │ │ ├── shared_prefs/ ← SharedPreferences │ │ └── cache/ ← getCacheDir() │ └── /data/app/ ← APK安装位置 ├── 外部存储 (内部SD需权限) │ ├── /storage/emulated/0/ │ │ ├── Download/ │ │ ├── DCIM/ │ │ └── Android/data/com.example.industrial/ │ │ ├── files/ ← getExternalFilesDir() │ │ └── cache/ ← getExternalCacheDir() └── 可移动存储 (U盘/SD卡) └── /storage/XXXX-XXXX/ ← 需要StorageManager枚举二、内部存储读写内部存储是应用专属的沙盒目录其他APP无法访问也不需要任何权限。2.1 常用路径获取方法// 1. 应用私有文件目录 - 推荐存放配置文件FilefilesDircontext.getFilesDir();// /data/user/0/com.example.industrial/files/// 2. 缓存目录 - 系统空间不足时会自动清理FilecacheDircontext.getCacheDir();// /data/user/0/com.example.industrial/cache/// 3. 数据库默认目录FiledatabaseDircontext.getDatabasePath(my_db);// /data/user/0/com.example.industrial/databases/my_db// 4. SharedPreferences目录// /data/user/0/com.example.industrial/shared_prefs/2.2 配置文件读写工控场景下设备参数采集频率、串口波特率、服务器地址等需要持久化存储。推荐方案publicclassConfigManager{privatestaticfinalStringCONFIG_FILEindustrial_config.json;// 存储到应用私有目录安全且不需要权限publicstaticvoidsaveConfig(Contextcontext,Stringjson){FileconfigFilenewFile(context.getFilesDir(),CONFIG_FILE);try(FileWriterwriternewFileWriter(configFile)){writer.write(json);}catch(IOExceptione){e.printStackTrace();}}publicstaticStringloadConfig(Contextcontext){FileconfigFilenewFile(context.getFilesDir(),CONFIG_FILE);if(!configFile.exists())returnnull;try{returnnewString(Files.readAllBytes(configFile.toPath()));}catch(IOExceptione){returnnull;}}}为什么用getFilesDir()而不是外部存储因为工控设备可能没有外置SD卡而且应用私有目录不需要权限、其他APP访问不了数据更安全。2.3 采集数据的存储策略对于大量传感器采集数据SQLite是最成熟的方案publicclassDataRepository{privateSQLiteDatabasedatabase;publicDataRepository(Contextcontext){DataDbHelperhelpernewDataDbHelper(context.getFilesDir().getAbsolutePath());databasehelper.getWritableDatabase();}publicvoidinsertSensorData(SensorDatadata){ContentValuesvaluesnewContentValues();values.put(temperature,data.temperature);values.put(humidity,data.humidity);values.put(timestamp,System.currentTimeMillis());database.insert(sensor_data,null,values);}// 定期清理旧数据防止存储爆满publicvoidcleanupOldData(longbeforeTimestamp){database.delete(sensor_data,timestamp ?,newString[]{String.valueOf(beforeTimestamp)});}}内部存储虽然安全但容量有限通常几个GB。对于长期运行且数据量大的工控设备需要定期清理或转存到外部存储。三、外部存储读写3.1 公有目录与私有目录// 公有目录 - 需要权限所有APP都能访问FiledownloadDirEnvironment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);// /storage/emulated/0/Download/// 应用私有外部目录 - Android 10不需要权限但需要用到分区存储APIFileexternalFilesDircontext.getExternalFilesDir(null);// /storage/emulated/0/Android/data/包名/files/// 应用外部缓存目录FileexternalCacheDircontext.getExternalCacheDir();// /storage/emulated/0/Android/data/包名/cache/在Android 10API 29之前直接使用Environment.getExternalStorageDirectory()获取根目录就行。但从Android 10开始引入分区存储Scoped Storage强制应用使用MediaStore API或SAF框架访问共享文件。工控设备如果跑的是Android 11需要在Manifest中声明uses-permissionandroid:nameandroid.permission.MANAGE_EXTERNAL_STORAGE/然后在代码中引导用户授权if(Build.VERSION.SDK_INTBuild.VERSION_CODES.R){if(!Environment.isExternalStorageManager()){IntentintentnewIntent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);startActivity(intent);}}3.2 日志文件导出到外部存储这是工控很常见的需求——设备出了问题需要把日志导出来查看publicstaticvoidexportLogs(Contextcontext){FilelogDirnewFile(context.getExternalFilesDir(null),logs);if(!logDir.exists())logDir.mkdirs();FilelogFilenewFile(logDir,app_newSimpleDateFormat(yyyyMMdd_HHmmss,Locale.US).format(newDate()).log);try(FileWriterwriternewFileWriter(logFile)){writer.write( 工控APP运行日志 \n);writer.write(版本: BuildConfig.VERSION_NAME\n);writer.write(设备: Build.MODEL\n);writer.write(SDK: Build.VERSION.SDK_INT\n);// 写入更多日志内容...}catch(IOExceptione){e.printStackTrace();}}四、U盘挂载检测与读写工控设备经常通过U盘做数据导入导出或固件升级这是工控和普通手机APP需求差异最大的地方。4.1 U盘挂载检测U盘插入后Android系统会自动挂载到/storage/下的某个目录通常是/storage/XXXX-XXXX/格式。我们需要通过StorageManager来获取挂载信息publicclassUsbStorageManager{privateStorageManagerstorageManager;publicUsbStorageManager(Contextcontext){storageManager(StorageManager)context.getSystemService(Context.STORAGE_SERVICE);}/** * 获取所有可移动存储设备的路径 */publicListFilegetRemovableVolumes(){ListFilevolumesnewArrayList();if(Build.VERSION.SDK_INTBuild.VERSION_CODES.N){ListStorageVolumestorageVolumesstorageManager.getStorageVolumes();for(StorageVolumevolume:storageVolumes){// 判断是否可移动存储if(volume.isRemovable()volume.getState().equals(Environment.MEDIA_MOUNTED)){FilevolumeDir;if(Build.VERSION.SDK_INTBuild.VERSION_CODES.R){volumeDirvolume.getDirectory();}else{// Android 10及以下用反射获取路径volumeDirgetVolumePathReflect(volume);}if(volumeDir!null){volumes.add(volumeDir);}}}}// 兼容性方案直接扫描 /storage/FilestorageDirnewFile(/storage/);File[]filesstorageDir.listFiles();if(files!null){for(Filefile:files){Stringnamefile.getName();// U盘挂载点通常是 XXXX-XXXX 格式if(!name.equals(emulated)!name.equals(self)file.canRead()file.listFiles()!null){if(!volumes.contains(file)){volumes.add(file);}}}}returnvolumes;}SuppressWarnings(JavaReflectionMemberAccess)privateFilegetVolumePathReflect(StorageVolumevolume){try{Class?clazzvolume.getClass();Methodmethod;if(Build.VERSION.SDK_INTBuild.VERSION_CODES.N){methodclazz.getMethod(getPathFile);}else{methodclazz.getMethod(getPath);}return(File)method.invoke(volume);}catch(Exceptione){returnnull;}}}4.2 U盘文件读写有了路径就可以用标准Java File API读写U盘了。下面是一个完整的文件读写工具类publicclassUsbFileManager{/** * 从U盘读取升级文件 */publicstaticFilefindUpgradeFile(FileusbRoot){File[]filesusbRoot.listFiles();if(filesnull)returnnull;for(Filefile:files){if(file.getName().toLowerCase().endsWith(.apk)||file.getName().toLowerCase().endsWith(.zip)){returnfile;}}returnnull;}/** * 将采集数据导出到U盘 */publicstaticbooleanexportDataToUsb(FileusbRoot,StringfileName,byte[]data){FileexportDirnewFile(usbRoot,IndustrialData);if(!exportDir.exists()){exportDir.mkdirs();}FileexportFilenewFile(exportDir,fileName);try(FileOutputStreamfosnewFileOutputStream(exportFile)){fos.write(data);fos.flush();returntrue;}catch(IOExceptione){e.printStackTrace();returnfalse;}}/** * 安全弹出U盘卸载文件系统 */publicstaticbooleanunmountUsb(StorageManagerstorageManager,StorageVolumevolume){try{// 通过Intent请求卸载兼容方案// 实际卸载需要系统签名普通APP只能通知用户拔出returntrue;}catch(Exceptione){returnfalse;}}}4.3 使用 Storage Access FrameworkSAFAndroid 4.4 引入了 SAF 框架可以不申请存储权限就访问外部存储publicclassSafHelper{privatestaticfinalintREQUEST_CODE_OPEN_DIR2001;publicstaticvoidopenDirectory(Activityactivity){IntentintentnewIntent(Intent.ACTION_OPEN_DOCUMENT_TREE);intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);activity.startActivityForResult(intent,REQUEST_CODE_OPEN_DIR);}publicstaticUrihandleResult(intrequestCode,intresultCode,Intentdata){if(requestCodeREQUEST_CODE_OPEN_DIRresultCodeActivity.RESULT_OK){UritreeUridata.getData();// 持久化权限下次启动还能用inttakeFlagsdata.getFlags()(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION);returntreeUri;}returnnull;}}对于工控场景SAF的缺点是每次都要用户手动选择目录不适合无人值守模式。建议如果设备跑Android 10以上就用分区存储API如果跑低版本直接走文件路径更省事。五、工控文件持久化方案选择数据类型推荐方案存储位置理由配置参数SharedPreferences / JSON文件getFilesDir()数据量小读写频繁采集数据SQLite数据库getDatabasePath()支持索引、事务、条件查询图片/视频文件系统getExternalFilesDir()文件大需定期清理日志文件文件系统getFilesDir() 定期导出私有目录安全导出到U盘固件升级包文件系统U盘 / 私有目录从U盘读取校验后复制到内部路径获取方法速查表// 内部存储 context.getFilesDir();// 应用私有文件context.getCacheDir();// 应用缓存context.getDatabasePath(name);// 数据库路径context.getDir(name,MODE_PRIVATE);// 自定义目录Environment.getDataDirectory();// /data// 外部存储内部SDEnvironment.getExternalStorageDirectory();// 根目录Android 10受限context.getExternalFilesDir(null);// 应用专属外部目录context.getExternalCacheDir();// 应用外部缓存Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);// 可移动存储 // 通过StorageManager枚举无标准API六、完整代码示例U盘数据采集与导出最后给出一个工控场景的完整示例——检测U盘插入后自动导出当天的采集数据publicclassUsbDataExporterextendsBroadcastReceiver{OverridepublicvoidonReceive(Contextcontext,Intentintent){if(!UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())){return;}// 延迟2秒等待挂载完成newHandler(Looper.getMainLooper()).postDelayed(()-{exportTodayData(context);},2000);}privatevoidexportTodayData(Contextcontext){StorageManagersm(StorageManager)context.getSystemService(Context.STORAGE_SERVICE);// 枚举可移动存储ListFileusbVolumesnewUsbStorageManager(context).getRemovableVolumes();if(usbVolumes.isEmpty()){Log.w(USB,未检测到可移动存储设备);return;}FileusbRootusbVolumes.get(0);StringtodayStrnewSimpleDateFormat(yyyyMMdd,Locale.US).format(newDate());// 从数据库导出今天的采集数据ListSensorDatatodayDataqueryTodayDataFromDb(context);StringBuildercsvBuildernewStringBuilder();csvBuilder.append(时间,温度,湿度,压力\n);for(SensorDatadata:todayData){csvBuilder.append(data.toCsvLine()).append(\n);}// 写入U盘booleansuccessUsbFileManager.exportDataToUsb(usbRoot,采集数据_todayStr.csv,csvBuilder.toString().getBytes(StandardCharsets.UTF_8));Log.i(USB,数据导出(success?成功:失败));}}Android存储看着复杂其实核心就三句话私有的放getFilesDir()、共享的放getExternalFilesDir()、U盘走 StorageManager 枚举路径。记住了这三句话工控文件管理就不怕迷路了。

相关新闻

HarmonyOs应用《日记本》开发第10篇 - @Builder 构建器与组件复用

HarmonyOs应用《日记本》开发第10篇 - @Builder 构建器与组件复用

2026/8/24 22:36:42

在 ArkUI 开发中,Builder 是实现 UI 片段复用的核心装饰器。它让开发者可以将复杂的 UI 拆分为多个可维护的方法,提高代码的可读性和复用性。本篇将以日记项目的三个页面为例,深入探讨 Builder 的使用模式和最佳实践。Builder 基本语法 Build…

LinkedIn资料完整,为什么还是很少收到招聘人员联系?|蒸汽求职分享

LinkedIn资料完整,为什么还是很少收到招聘人员联系?|蒸汽求职分享

2026/8/24 22:36:42

**摘要:**LinkedIn资料完整,只能说明页面信息较齐全,并不代表招聘人员能快速判断候选人适合什么岗位。Headline、About、经历标题和项目描述需要共同传递清楚的职业方向,同时保持信息真实,并与简历和实际能力一致。 学…

为什么你的AI采集系统总在凌晨崩?揭秘内存泄漏×JS沙箱逃逸×Token轮换失效的三重连锁故障(附热修复补丁)

为什么你的AI采集系统总在凌晨崩?揭秘内存泄漏×JS沙箱逃逸×Token轮换失效的三重连锁故障(附热修复补丁)

2026/8/24 22:36:42

更多请点击: https://kaifayun.com 第一章:AI自动化 数据采集 AI驱动的数据采集正逐步取代传统手动爬取与人工录入模式,其核心在于将感知、决策与执行能力嵌入采集流程中。现代AI自动化采集系统通常融合自然语言处理(NLP&#xf…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/21 18:38:46

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/21 18:41:09

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/21 18:36:40

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/21 18:37:26

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/21 18:40:29

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/21 18:36:17

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/22 0:19:28

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/21 23:38:13

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/22 0:48:53

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…