第十九天 HarmonyOS的文件操作和本地存储

news2025/2/25 22:27:11

一、前言:为什么需要掌握文件操作与本地存储?

在移动应用开发中,文件操作和本地存储是每个开发者都必须掌握的核心技能。无论是保存用户配置、缓存网络数据,还是处理图片/视频等多媒体文件,都需要通过文件系统进行操作。在HarmonyOS开发中,系统提供了完善的API体系和沙箱安全机制,帮助开发者实现安全高效的本地存储。

二、HarmonyOS文件系统基础

2.1 沙箱机制解析

HarmonyOS为每个应用分配独立的存储空间,采用沙箱机制隔离不同应用的数据。通过实际路径对比理解这个机制:

// 应用私有目录路径示例
context.getFilesDir()/data/app/el2/100/base/com.example.demo/haps/entry/files

2.2 存储区域划分

存储类型访问权限清除策略
应用私有目录仅本应用可读写卸载自动清除
公共目录需申请权限持久保存
缓存目录自动管理空间不足时清除

三、四大本地存储方案实战

3.1 应用私有文件操作(基础版)

完整文件读写示例:

// 获取文件目录
File filesDir = getContext().getFilesDir();

// 写入文件
try (FileOutputStream fos = new FileOutputStream(new File(filesDir, "config.txt"))) {
    fos.write("Hello HarmonyOS".getBytes());
} catch (IOException e) {
    HiLog.error(LABEL, "文件写入失败: " + e.getMessage());
}

// 读取文件
StringBuilder content = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(new File(filesDir, "config.txt")))) {
    String line;
    while ((line = br.readLine()) != null) {
        content.append(line);
    }
} catch (IOException e) {
    HiLog.error(LABEL, "文件读取失败: " + e.getMessage());
}

3.2 Preferences轻量存储

键值对存储最佳实践:

// 初始化Preferences实例
Preferences preferences = Preferences.getGlobalPreferences(context);

// 存储数据
preferences.putString("userName", "Harmony开发者")
          .putInt("loginCount", 5)
          .flush(); // 立即提交

// 读取数据
String name = preferences.getString("userName", "默认值");
int count = preferences.getInt("loginCount", 0);

// 监听数据变化
preferences.registerObserver((key) -> {
    if ("themeMode".equals(key)) {
        updateTheme(preferences.getString(key, "light"));
    }
});

3.3 关系型数据库(RelationalStore)

数据库操作四部曲:

步骤1:定义实体类

@Entity
public class User {
    @PrimaryKey
    private Integer id;
    
    @ColumnInfo(name = "user_name")
    private String name;
    
    // Getter/Setter省略...
}

步骤2:创建数据库

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends HarmonyOSOpenHelper {
    private static final String DB_NAME = "user_db";
    
    public AppDatabase(Context context) {
        super(context, DB_NAME, null);
    }
}

步骤3:实现DAO接口

@Dao
public interface UserDao {
    @Insert
    void insertUser(User user);
    
    @Query("SELECT * FROM User WHERE id = :userId")
    User getUserById(int userId);
}

步骤4:业务层调用

UserDao userDao = DatabaseHolder.getDatabase().userDao();
userDao.insertUser(new User(1, "张三"));

User user = userDao.getUserById(1);
HiLog.info(LABEL, "查询结果:" + user.getName());

3.4 对象存储(ObjectStore)

复杂对象存储方案:

// 创建对象存储
ObjectStore objectStore = ObjectStore.create(context, "MyObjectStore");

// 存储自定义对象
User user = new User("李四", 25);
objectStore.put("current_user", user);

// 读取对象
User cachedUser = objectStore.get("current_user", User.class);

四、综合实战:备忘录应用开发

4.1 项目结构设计

src/main/java/
├── entry
│   ├── MainAbility.java       # 主界面
│   ├── Note.java             # 笔记实体类
│   ├── NoteDatabase.java     # 数据库类
│   └── NoteDao.java          # 数据操作接口
resources/
└── config.json               # 配置文件

4.2 核心功能实现

笔记保存功能:

public void saveNote(String title, String content) {
    Note newNote = new Note();
    newNote.setTitle(title);
    newNote.setContent(content);
    newNote.setCreateTime(new Date());
    
    // 同时保存到数据库和本地文件
    noteDao.insert(newNote);
    saveToFile(title + ".txt", content);
}

private void saveToFile(String fileName, String content) {
    File targetFile = new File(getExternalFilesDir("notes"), fileName);
    try (FileWriter writer = new FileWriter(targetFile)) {
        writer.write(content);
    } catch (IOException e) {
        HiLog.error(LABEL, "文件保存失败:" + e.getMessage());
    }
}

笔记列表展示:

ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_note_list);
List<Note> notes = noteDao.getAllNotes();

SampleItemProvider provider = new SampleItemProvider(notes, this);
listContainer.setItemProvider(provider);

五、高级技巧与优化策略

5.1 大文件分块传输

private static final int BUFFER_SIZE = 1024 * 1024; // 1MB缓冲区

void copyLargeFile(File source, File target) throws IOException {
    try (InputStream is = new FileInputStream(source);
         OutputStream os = new FileOutputStream(target)) {
         
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead;
        while ((bytesRead = is.read(buffer)) != -1) {
            os.write(buffer, 0, bytesRead);
            updateProgress(bytesRead); // 更新进度条
        }
    }
}

5.2 数据库事务优化

noteDatabase.beginTransaction();
try {
    for (int i = 0; i < 1000; i++) {
        Note note = generateTestNote(i);
        noteDao.insert(note);
    }
    noteDatabase.setTransactionSuccessful();
} finally {
    noteDatabase.endTransaction();
}

六、常见问题排查指南

6.1 权限问题处理方案

<!-- config.json添加权限声明 -->
"reqPermissions": [
    {
        "name": "ohos.permission.READ_USER_STORAGE",
        "reason": "需要读取用户文件"
    },
    {
        "name": "ohos.permission.WRITE_USER_STORAGE",
        "reason": "需要写入用户文件"
    }
]

6.2 存储空间监控

FileStat stat = new FileStat();
FileStat.getStat(path, stat);
long freeSpace = stat.blockSize * stat.blocksFree;

if (freeSpace < 1024 * 1024 * 100) { // 剩余空间小于100MB
    showCleanStorageDialog();
}

七、总结与学习建议

通过本文的学习,你应该已经掌握:

  • ✔️ 文件系统的沙箱机制与路径获取
  • ✔️ Preferences键值对存储的灵活应用
  • ✔️ RelationalStore数据库的CRUD操作
  • ✔️ 对象存储的使用场景
  • ✔️ 综合项目的开发实践

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306042.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FFMPEG编码容错处理解决办法之途径----升级库文件

在qt开发环境下接收网络数据&#xff0c;调用ffmpeg解码播放视频&#xff0c;出现闪屏现象&#xff0c;具体现象可以使用操作系统自带的ffplay播放器播放原始视频流可复现&#xff1b;而使用操作系统自带的mpv播放器播放视频则不会出现闪屏&#xff1b;闪屏时会报Could not fin…

uniapp h5端和app端 使用 turn.js

前提:添加页后,添加页与当前页会重叠在一起,不知道为什么,没有找到解决办法 1.h5端 <template><view class"container"><view id"flipbook"><view class"page page1">Page 1</view><view class"page pag…

【入门音视频】音视频基础知识

&#x1f308;前言&#x1f308; 这个系列在我学习过程中&#xff0c;对音视频知识归纳总结的笔记。因为音视频相关讲解非常稀少&#xff0c;所以我希望通过这个音视频系列&#xff0c;跟大家一起学习音视频&#xff0c;希望减少初学者在学习上的压力。同时希望也欢迎指出文章的…

数据结构☞泛型

一.基础定义与应用方向 1.定义&#xff1a; 一般的类和方法&#xff0c;只能使用具体的类型 : 要么是基本类型&#xff0c;要么是自定义的类。如果要编写可以 应用于多种类型 的代码&#xff0c;这种刻板的限制对代码的束缚就会很大。----- 来源《 Java 编程思想》对泛型的介…

hot100-二叉树

二叉树 二叉树递归 相当于这个的顺序来回调换 class Solution {private List<Integer> res new ArrayList<>();public List<Integer> inorderTraversal(TreeNode root) {if(root null)return res;inorderTraversal(root.left);res.add(root.val);inorde…

嵌入式项目:STM32刷卡指纹智能门禁系统

本文详细介绍基于STM32的刷卡指纹智能门禁系统。 获取资料/指导答疑/技术交流/选题/帮助&#xff0c;请点链接&#xff1a; https://gitee.com/zengzhaorong/share_contact/blob/master/stm32.txt 1 系统功能 1.1 功能概述 本系统由STM32硬件端&#xff08;下位机&#xff09;…

短剧小程序系统源码

短剧小程序系统源码 今天我要向大家介绍的是最新作品——短剧小程序系统源码。这不仅仅是一款简单的播放工具&#xff0c;它背后蕴含的强大功能能够帮助你的短剧业务实现质的飞跃&#xff01; 为什么说这款源码很厉害&#xff1f; 首先&#xff0c;在当今竞争激烈的市场环境…

C#中级教程(2)——走进 C# 面向对象编程:从基础到进阶的深度探索

一、为什么选择面向对象编程 在软件开发的演进过程中&#xff0c;随着程序规模和复杂度的不断增加&#xff0c;传统的编程方式逐渐暴露出局限性。面向对象编程应运而生&#xff0c;它就像是一位智慧的组织者&#xff0c;将程序中的功能进行模块化划分。每个模块各司其职&#x…

基于SpringBoot的“流浪动物救助系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“流浪动物救助系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 局部E-R图 系统首页界面 系统…

基于WebRTC与AI大模型接入EasyRTC:打造轻量级、高实时、强互动的嵌入式音视频解决方案

随着物联网和嵌入式技术的快速发展&#xff0c;嵌入式设备对实时音视频通信的需求日益增长。然而&#xff0c;传统的音视频解决方案往往存在体积庞大、实时性差、互动体验不佳等问题&#xff0c;难以满足嵌入式设备的资源限制和应用场景需求。 针对以上痛点&#xff0c;本文将介…

Windows - 通过ssh打开带有图形界面的程序 - 一种通过计划任务的曲折实现方式

Windows(奇思妙想) - 通过ssh打开带有图形界面的程序 - 一种通过计划任务的曲折实现方式 前言 Windows启用OpenSSH客户端后就可以通过SSH的方式访问Windows了。但是通过SSH启动的程序&#xff1a; 无法显示图形界面会随着SSH进程的结束而结束 于是想到了一种通过执行“计划…

RT-Thread+STM32L475VET6——USB鼠标模拟

文章目录 前言一、板载资源二、具体步骤1.配置icm20608传感器2.打开CubeMX进行USB配置3. 配置USB3.1 打开USB驱动3.2 声明USB3.3 剪切stm32xxxx_hal_msp.c中的void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)和void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)函数至board.c3.…

计算机毕业设计SpringBoot+Vue.js母婴商城(源码+LW文档+PPT+讲解+开题报告)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Teigha(ODA<Open Design Alliance>_开放设计联盟)——cad c# 二次开发

需将dll库文件与exe文件放同一路径下&#xff0c;运行exe即可执行。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Thread…

idea 部署 AJ-Report 启动的注意事项

AJ-Report 入门参考&#xff1a; AJ-Report 初学(入门教程) gitee 下载&#xff1a;https://gitee.com/anji-plus/report/releases 根据上面提供的 gitee 下载链接&#xff0c;点击直接下载 最上面的就是最新版本的&#xff0c;旧版本往下拉就可以找到&#xff0c;有三个下载…

智能化客户行为轨迹分析:AI视频监控在大型商场的技术方案

项目背景&#xff1a;为了提升顾客体验并支持精准营销&#xff0c;卖场或商场需要通过智能化手段分析客户在商场内的行为路线。 一、具体需求 1、行为路径分析&#xff1a;跟踪顾客在商场内的移动轨迹&#xff0c;了解顾客的购物习惯和偏好。 2、高频活动区域识别&#xff1a…

Denoising Diffusion Restoration Models论文解读

论文要点 恢复的线性逆问题可以使用预训练的DDPM完成&#xff1a;1. 将降质矩阵使用SVD&#xff0c;得到分解矩阵&#xff1b;2. 使用分解矩阵将图像投影到降质类型间共享的谱空间&#xff1b;3. 谱空间中执行DDPM。 评价 同Track的方法同样很多&#xff0c;比如后续的DDNM、…

基于SpringBoot的校园消费点评管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【NLP 38、激活函数 ④ GELU激活函数】

别盲目&#xff0c;别着急&#xff0c;慢慢走&#xff0c;没事的 —— 25.2.24 一、定义与数学表达式 GELU&#xff08;Gaussian Error Linear Unit&#xff0c;高斯误差线性单元&#xff09;是一种结合概率分布的非线性激活函数&#xff0c;其核心思想是通过输入值服从标准正…

QT:paintEvent、QPainter、QPaintDevice

paintEvent 介绍 在 Qt 编程中&#xff0c;paintEvent 是 QWidget 类中的一个非常重要的虚函数&#xff0c;用于处理绘图事件。当一个 QWidget 或其派生类的实例需要进行重绘操作时&#xff0c;Qt 会自动调用该控件的 paintEvent 函数。 触发时机 窗口首次显示&#xff1a;当…