鸿蒙文件操作完全指南:从基础到实战
在鸿蒙应用开发中,文件操作是必不可少的功能。无论是保存用户数据、缓存网络资源还是管理应用文件,都需要用到文件系统。今天我们来全面学习鸿蒙中的文件操作api。
鸿蒙文件操作基础
鸿蒙提供了两个主要模块来处理文件:
@ohos.fileio - 基础文件IO操作
@ohos.file.fs - 文件系统高级功能
基础文件操作
检查文件或目录是否存在
在操作文件之前,通常需要先检查文件是否存在。
import fileio from '@ohos.fileio';
import fs from '@ohos.file.fs';
// 检查文件是否存在
function checkFileExists(filePath: string): boolean {
try {
const fileStats = fs.statSync(filePath);
return fileStats.isFile();
} catch (error) {
return false;
}
}
// 检查目录是否存在
function checkDirectoryExists(dirPath: string): boolean {
try {
const dirStats = fs.statSync(dirPath);
return dirStats.isDirectory();
} catch (error) {
return false;
}
}
// 使用示例
const configPath = '/data/storage/el2/base/config.json';
if (checkFileExists(configPath)) {
console.log('配置文件存在');
} else {
console.log('配置文件不存在');
}创建文件和目录
创建文件目录是文件操作的基础。
// 创建单个文件
function createNewFile(filePath: string): boolean {
try {
// 打开文件时如果不存在会自动创建
const fileDescriptor = fs.openSync(filePath,
fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
fs.closeSync(fileDescriptor);
return true;
} catch (error) {
console.error('创建文件失败:', error.message);
return false;
}
}
// 创建单个目录
function createNewDirectory(dirPath: string): boolean {
try {
fs.mkdirSync(dirPath);
return true;
} catch (error) {
console.error('创建目录失败:', error.message);
return false;
}
}
// 递归创建多级目录
function createDirectoriesRecursive(fullPath: string): boolean {
const parentDir = fileio.dirname(fullPath);
// 如果父目录不存在,先创建父目录
if (!checkDirectoryExists(parentDir)) {
createDirectoriesRecursive(parentDir);
}
return createNewDirectory(fullPath);
}
// 使用示例:创建日志目录
const logDir = '/data/storage/el2/base/logs/app';
if (createDirectoriesRecursive(logDir)) {
console.log('日志目录创建成功');
}删除文件和目录
文件清理也是重要的文件操作。
// 删除文件
function removeFile(filePath: string): boolean {
try {
fs.unlinkSync(filePath);
return true;
} catch (error) {
console.error('删除文件失败:', error.message);
return false;
}
}
// 删除空目录
function removeEmptyDirectory(dirPath: string): boolean {
try {
fs.rmdirSync(dirPath);
return true;
} catch (error) {
console.error('删除目录失败:', error.message);
return false;
}
}
// 递归删除目录及其所有内容
function removeDirectoryRecursive(dirPath: string): boolean {
try {
const files = fs.listFileSync(dirPath);
files.forEach(fileName => {
const currentPath = `${dirPath}/${fileName}`;
const stats = fs.statSync(currentPath);
if (stats.isDirectory()) {
// 如果是目录,递归删除
removeDirectoryRecursive(currentPath);
} else {
// 如果是文件,直接删除
removeFile(currentPath);
}
});
// 删除空目录
return removeEmptyDirectory(dirPath);
} catch (error) {
console.error('递归删除目录失败:', error.message);
return false;
}
}文件读写操作
同步文件读写
同步操作适合处理小文件,代码更简单。
// 同步读取文件内容
function readFileContent(filePath: string): string | null {
try {
const fileDescriptor = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
const fileStats = fs.statSync(filePath);
// 创建缓冲区
const buffer = new ArrayBuffer(fileStats.size);
fs.readSync(fileDescriptor, buffer);
fs.closeSync(fileDescriptor);
// 将二进制数据转换为字符串
const uint8Array = new Uint8Array(buffer);
return String.fromCharCode.apply(null, Array.from(uint8Array));
} catch (error) {
console.error('读取文件失败:', error.message);
return null;
}
}
// 同步写入文件内容
function writeFileContent(filePath: string, content: string): boolean {
try {
const fileDescriptor = fs.openSync(filePath,
fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
// 将字符串转换为二进制数据
const buffer = new ArrayBuffer(content.length);
const uint8Array = new Uint8Array(buffer);
for (let i = 0; i < content.length; i++) {
uint8Array[i] = content.charCodeAt(i);
}
fs.writeSync(fileDescriptor, buffer);
fs.closeSync(fileDescriptor);
return true;
} catch (error) {
console.error('写入文件失败:', error.message);
return false;
}
}
// 追加内容到文件
function appendToFile(filePath: string, content: string): boolean {
try {
const fileDescriptor = fs.openSync(filePath,
fs.OpenMode.READ_WRITE | fs.OpenMode.APPEND);
const buffer = new ArrayBuffer(content.length);
const uint8Array = new Uint8Array(buffer);
for (let i = 0; i < content.length; i++) {
uint8Array[i] = content.charCodeAt(i);
}
fs.writeSync(fileDescriptor, buffer);
fs.closeSync(fileDescriptor);
return true;
} catch (error) {
console.error('追加文件失败:', error.message);
return false;
}
}
// 使用示例:保存用户配置
const userConfig = {
theme: 'dark',
language: 'zh-CN',
notifications: true
};
const configPath = '/data/storage/el2/base/user_config.json';
if (writeFileContent(configPath, JSON.stringify(userConfig))) {
console.log('用户配置保存成功');
}异步文件读写
异步操作不会阻塞主线程,适合处理大文件。
// 异步读取文件
async function readFileAsync(filePath: string): Promise<string | null> {
return new Promise((resolve) => {
fs.open(filePath, fs.OpenMode.READ_ONLY, (openError, fileDescriptor) => {
if (openError) {
console.error('打开文件失败:', openError.message);
resolve(null);
return;
}
fs.stat(filePath, (statError, fileStats) => {
if (statError) {
console.error('获取文件信息失败:', statError.message);
fs.close(fileDescriptor);
resolve(null);
return;
}
const buffer = new ArrayBuffer(fileStats.size);
fs.read(fileDescriptor, buffer, (readError, bytesRead) => {
fs.close(fileDescriptor);
if (readError) {
console.error('读取文件失败:', readError.message);
resolve(null);
return;
}
const uint8Array = new Uint8Array(buffer);
const content = String.fromCharCode.apply(null, Array.from(uint8Array));
resolve(content);
});
});
});
});
}
// 异步写入文件
async function writeFileAsync(filePath: string, content: string): Promise<boolean> {
return new Promise((resolve) => {
fs.open(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE,
(openError, fileDescriptor) => {
if (openError) {
console.error('打开文件失败:', openError.message);
resolve(false);
return;
}
const buffer = new ArrayBuffer(content.length);
const uint8Array = new Uint8Array(buffer);
for (let i = 0; i < content.length; i++) {
uint8Array[i] = content.charCodeAt(i);
}
fs.write(fileDescriptor, buffer, (writeError, bytesWritten) => {
fs.close(fileDescriptor);
if (writeError) {
console.error('写入文件失败:', writeError.message);
resolve(false);
return;
}
resolve(true);
});
});
});
}
// 使用示例:异步读取日志文件
async function displayLogs() {
const logPath = '/data/storage/el2/base/logs/app.log';
const logContent = await readFileAsync(logPath);
if (logContent) {
console.log('日志内容:', logContent);
} else {
console.log('读取日志失败');
}
}文件流操作
处理大文件时,使用流可以节省内存。
// 创建文件读取流
function createFileReadStream(filePath: string): fileio.Stream | null {
try {
return fileio.createStream(filePath, 'r');
} catch (error) {
console.error('创建读取流失败:', error.message);
return null;
}
}
// 创建文件写入流
function createFileWriteStream(filePath: string): fileio.Stream | null {
try {
return fileio.createStream(filePath, 'w');
} catch (error) {
console.error('创建写入流失败:', error.message);
return null;
}
}
// 使用流复制大文件
async function copyLargeFile(sourcePath: string, targetPath: string): Promise<boolean> {
return new Promise((resolve) => {
const readStream = createFileReadStream(sourcePath);
const writeStream = createFileWriteStream(targetPath);
if (!readStream || !writeStream) {
resolve(false);
return;
}
readStream.on('data', (chunk) => {
writeStream.write(chunk);
});
readStream.on('end', () => {
writeStream.close();
resolve(true);
});
readStream.on('error', (error) => {
console.error('读取流错误:', error.message);
writeStream.close();
resolve(false);
});
writeStream.on('error', (error) => {
console.error('写入流错误:', error.message);
resolve(false);
});
});
}高级文件操作
文件属性管理
// 获取文件详细信息
function getFileInfo(filePath: string): fs.Stat | null {
try {
return fs.statSync(filePath);
} catch (error) {
console.error('获取文件信息失败:', error.message);
return null;
}
}
// 获取文件大小
function getFileSize(filePath: string): number | null {
const stats = getFileInfo(filePath);
return stats ? stats.size : null;
}
// 获取文件修改时间
function getFileModifyTime(filePath: string): number | null {
const stats = getFileInfo(filePath);
return stats ? stats.mtime : null;
}
// 修改文件权限
function changeFilePermissions(filePath: string, mode: number): boolean {
try {
fs.chmodSync(filePath, mode);
return true;
} catch (error) {
console.error('修改文件权限失败:', error.message);
return false;
}
}路径操作工具
// 获取文件扩展名
function getFileExtension(filePath: string): string {
const fileName = fileio.basename(filePath);
const dotIndex = fileName.lastIndexOf('.');
return dotIndex === -1 ? '' : fileName.slice(dotIndex + 1);
}
// 获取文件名(不含扩展名)
function getFileNameWithoutExtension(filePath: string): string {
const fileName = fileio.basename(filePath);
const dotIndex = fileName.lastIndexOf('.');
return dotIndex === -1 ? fileName : fileName.slice(0, dotIndex);
}
// 安全拼接路径
function joinPathSegments(...segments: string[]): string {
return segments.join('/').replace(/\/+/g, '/');
}
// 使用示例
const baseDir = '/data/storage/el2/base';
const fileName = 'config.json';
const fullPath = joinPathSegments(baseDir, 'config', fileName);
console.log('完整路径:', fullPath);实战:文件工具类
下面是一个完整的文件工具类,封装了常用的文件操作。
import fs from '@ohos.file.fs';
import fileio from '@ohos.fileio';
class FileManager {
// 检查文件是否存在
static exists(path: string): boolean {
try {
fs.statSync(path);
return true;
} catch {
return false;
}
}
// 读取文本文件
static readTextFile(path: string): string | null {
try {
if (!this.exists(path)) {
return null;
}
const fd = fs.openSync(path, fs.OpenMode.READ_ONLY);
const stats = fs.statSync(path);
const buffer = new ArrayBuffer(stats.size);
fs.readSync(fd, buffer);
fs.closeSync(fd);
const uint8Array = new Uint8Array(buffer);
return String.fromCharCode.apply(null, Array.from(uint8Array));
} catch (error) {
console.error('读取文件失败:', error.message);
return null;
}
}
// 写入文本文件
static writeTextFile(path: string, content: string): boolean {
try {
const fd = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
const buffer = new ArrayBuffer(content.length);
const uint8Array = new Uint8Array(buffer);
for (let i = 0; i < content.length; i++) {
uint8Array[i] = content.charCodeAt(i);
}
fs.writeSync(fd, buffer);
fs.closeSync(fd);
return true;
} catch (error) {
console.error('写入文件失败:', error.message);
return false;
}
}
// 读取JSON文件
static readJSONFile<T>(path: string): T | null {
const content = this.readTextFile(path);
if (!content) return null;
try {
return JSON.parse(content) as T;
} catch {
return null;
}
}
// 写入JSON文件
static writeJSONFile(path: string, data: any): boolean {
try {
const content = JSON.stringify(data, null, 2);
return this.writeTextFile(path, content);
} catch (error) {
console.error('写入JSON文件失败:', error.message);
return false;
}
}
// 复制文件
static copyFile(source: string, target: string): boolean {
try {
fs.copyFileSync(source, target);
return true;
} catch (error) {
console.error('复制文件失败:', error.message);
return false;
}
}
// 列出目录内容
static listDirectory(path: string): string[] | null {
try {
return fs.listFileSync(path);
} catch (error) {
console.error('列出目录失败:', error.message);
return null;
}
}
// 创建临时文件
static createTempFile(prefix: string = 'temp'): string | null {
try {
return fs.createTempFileSync(prefix);
} catch (error) {
console.error('创建临时文件失败:', error.message);
return null;
}
}
}
// 使用示例
const config = FileManager.readJSONFile<{ theme: string }>('/data/storage/el2/base/config.json');
if (config) {
console.log('当前主题:', config.theme);
}
// 保存用户数据
const userData = { name: '张三', age: 25 };
FileManager.writeJSONFile('/data/storage/el2/base/userdata.json', userData);重要注意事项
权限配置
在config.json中声明文件权限:
{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.READ_MEDIA",
"reason": "读取用户文件"
},
{
"name": "ohos.permission.WRITE_MEDIA",
"reason": "保存用户数据"
}
]
}
}性能建议
小文件:使用同步操作,代码简单
大文件:使用异步操作或流操作,避免阻塞
频繁操作:考虑使用缓存减少IO次数
错误处理
所有文件操作都要做好错误处理:
try {
const content = FileManager.readTextFile('/path/to/file');
if (content) {
// 处理文件内容
}
} catch (error) {
console.error('文件操作失败:', error.message);
// 给用户友好的错误提示
}总结
鸿蒙的文件操作API功能丰富,从基础的文件读写到高级的流操作都有很好的支持。关键是要根据具体场景选择合适的操作方式:
配置文件和用户数据:使用同步读写
日志文件和大文件:使用异步或流操作
临时数据:使用临时文件API
文件管理:使用目录操作API
掌握这些文件操作技巧,你就能在鸿蒙应用中轻松处理各种文件相关的需求了。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!