在这里插入图片描述

摘要

本文通过鸿蒙文件管理API实现一个具有实用价值的笔记应用,涵盖权限申请、文件读写、异常处理等核心功能。你将学会如何安全地保存用户笔记到外部存储,并在应用启动时自动加载历史记录。

描述

在移动应用中,本地文件存储是基础且关键的功能。鸿蒙的分布式文件系统为开发者提供了统一的文件操作接口,但实际开发中常遇到权限管理、路径处理、读写效率等问题。我们将通过一个笔记应用场景,演示如何优雅地解决这些问题。

题解答案

// NoteManager.java - 核心文件操作类
package com.example.notedemo;

import ohos.app.Context;
import ohos.data.storage.FileIO;
import ohos.environment.Environment;
import ohos.global.resource.RawFileDescriptor;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.io.File;
import java.io.IOException;

public class NoteManager {
    private static final HiLogLabel LABEL = new HiLogLabel(0, 0, "NoteManager");
    private final Context context;
    private final String notePath;

    public NoteManager(Context context) {
        this.context = context;
        // 构建笔记存储路径:/sdcard/NoteDemo/notes.txt
        File externalDir = Environment.getExternalStorageDirectory();
        File appDir = new File(externalDir, "NoteDemo");
        if (!appDir.exists() && !appDir.mkdirs()) {
            HiLog.error(LABEL, "Failed to create directory");
        }
        this.notePath = appDir.getAbsolutePath() + File.separator + "notes.txt";
    }

    // 保存笔记内容
    public boolean saveNote(String content) {
        try {
            // 追加写入模式
            RawFileDescriptor fd = FileIO.openRawFileDescriptor(notePath, "wa");
            if (fd == null) return false;
            
            // 添加时间戳和分隔符
            String record = "\n--- " + System.currentTimeMillis() + " ---\n" + content;
            FileIO.write(fd, record.getBytes());
            FileIO.closeRawFileDescriptor(fd);
            return true;
        } catch (IOException e) {
            HiLog.error(LABEL, "Save failed: " + e.getMessage());
            return false;
        }
    }

    // 读取历史笔记
    public String loadNotes() {
        File file = new File(notePath);
        if (!file.exists()) return "No notes yet";
        
        try {
            RawFileDescriptor fd = FileIO.openRawFileDescriptor(notePath, "r");
            if (fd == null) return "Read error";
            
            byte[] data = FileIO.read(fd);
            FileIO.closeRawFileDescriptor(fd);
            return new String(data);
        } catch (IOException e) {
            HiLog.error(LABEL, "Load failed: " + e.getMessage());
            return "Load error";
        }
    }
}
// MainAbilitySlice.java - 界面逻辑处理
package com.example.notedemo;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Text;
import ohos.agp.components.TextField;
import ohos.security.SystemPermission;

public class MainAbilitySlice extends AbilitySlice {
    private NoteManager noteManager;
    private TextField inputField;
    private Text displayArea;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        
        // 初始化组件
        inputField = (TextField) findComponentById(ResourceTable.Id_note_input);
        displayArea = (Text) findComponentById(ResourceTable.Id_note_display);
        Button saveBtn = (Button) findComponentById(ResourceTable.Id_save_btn);
        
        // 检查存储权限
        if (!canRequestPermission(SystemPermission.WRITE_USER_STORAGE)) {
            requestPermissionsFromUser(
                new String[]{SystemPermission.WRITE_USER_STORAGE}, 
                0
            );
        } else {
            initFileManager();
        }
        
        // 保存按钮事件
        saveBtn.setClickedListener(component -> {
            if (noteManager == null) return;
            String content = inputField.getText();
            if (!content.isEmpty()) {
                boolean success = noteManager.saveNote(content);
                displayArea.setText(success ? "Saved!" : "Save failed");
                inputField.setText("");
            }
        });
    }

    private void initFileManager() {
        noteManager = new NoteManager(getContext());
        // 启动时加载历史记录
        displayArea.setText(noteManager.loadNotes());
    }

    @Override
    public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
        if (grantResults[0] == 0) { // 0表示授权成功
            initFileManager();
        } else {
            displayArea.setText("Permission denied! Function limited");
        }
    }
}

题解代码分析

** 文件路径管理**

File externalDir = Environment.getExternalStorageDirectory();
File appDir = new File(externalDir, "NoteDemo");
  • 使用Environment获取标准外部存储路径
  • 创建应用专属目录避免文件混乱
  • 路径示例:/sdcard/NoteDemo/notes.txt

** 安全文件写入**

RawFileDescriptor fd = FileIO.openRawFileDescriptor(notePath, "wa");
FileIO.write(fd, record.getBytes());
  • "wa"模式表示追加写入,保留历史记录
  • 自动添加时间戳分隔符--- 1623825360000 ---
  • 字节流写入确保编码一致性

** 权限动态处理**

requestPermissionsFromUser(
    new String[]{SystemPermission.WRITE_USER_STORAGE}, 
    0
);
  • 首次启动时触发权限弹窗
  • 授权结果在onRequestPermissionsFromUserResult回调
  • 优雅降级处理(权限拒绝时提示用户)

** 异常防护机制**

} catch (IOException e) {
    HiLog.error(LABEL, "Save failed: " + e.getMessage());
    return false;
}
  • 捕获IO异常防止崩溃
  • 使用HiLog输出错误详情到控制台
  • 返回操作状态供UI反馈

示例测试及结果

测试场景1:首次保存笔记
输入文本:“鸿蒙开发初体验”
点击保存按钮
界面显示"Saved!"
文件内容:

--- 1623825360000 ---
鸿蒙开发初体验

测试场景2:追加新笔记
输入文本:“文件API很简洁”
点击保存
文件内容追加:

--- 1623825360000 ---
鸿蒙开发初体验
--- 1623825420000 ---
文件API很简洁

测试场景3:启动时加载
关闭应用重新打开
自动显示:

--- 1623825360000 ---
鸿蒙开发初体验
--- 1623825420000 ---
文件API很简洁

异常测试:

  • 禁用存储权限 → 显示"Permission denied"
  • 存储空间不足 → 日志输出"Save failed: No space left"

时间复杂度

  • 写入操作:O(n)
    • 与笔记内容长度线性相关
    • 追加写入不影响已有内容
  • 读取操作:O(n)
    • 需加载整个文件内容
    • 建议分页加载处理大文件

空间复杂度

  • 固定开销:路径字符串+文件描述符
  • 动态开销:笔记内容字节数组
  • 存储优化建议:
    • 超长文本分块存储
    • 定期归档历史笔记

总结

通过这个实战案例,我们掌握了鸿蒙文件管理的核心要点:
权限管理:动态申请存储权限并处理拒绝场景
路径规范:使用Environment获取标准路径
安全读写:try-catch防护+资源及时关闭
用户反馈:实时操作状态提示

实际开发中还可扩展:

  • 添加图片附件支持(使用MediaLibrary
  • 实现跨设备同步(分布式文件系统)
  • 自动备份到云存储(集成华为云服务)
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐