文件系统设计 - 开发文件系统 Store (上篇)

本节开始,我们将从最核心基础的文件系统进行设计实现,构建文件系统Store

一个基础的响应式Store类

Vue3 开始,Vue响应式借助Proxy重构后,整个响应式系统的应用变得非常的灵活,虽然目前业界依旧有 Pinia 等响应式管理库,但其本质依旧是在借助Vue的响应式API进行设计实现;所以很多时候其实并非需要第三方的响应式管理库,如果只是简单的响应式处理直接借助 Vue 的响应式API即可。

关于Vue3 的响应式实现细节,大家可以参考网上很多的Vue原理解析文章,或者大家有兴趣可以在下方留言,后面也可以出一期从0手写mini-vue3 源码的专栏

这里我们便借助 Vue 的响应式API封装一个具有响应式State管理的基类

import { reactive, UnwrapNestedRefs } from 'vue'

export abstract class Store<T extends Record<string, unknown>> {
  state: UnwrapNestedRefs<T>;

  constructor(state: T) {
    this.state = reactive(state);
  }
}

设计文件系统类接口

web端的编辑器虽然可以借助 File System Access API 对本地文件进行操作,但是因其兼容性问题,目前Web编辑器的文件还是存在内存中的,将文件以树型结构在内存中进行存储维护,所以首先我们先明确文件系统的主要作用是: 管理内存中的文件树; 这里的管理主要包括以下部分:

  • 创建文件/文件夹
  • 删除文件/文件夹
  • 查找文件/文件夹
  • 移动文件/文件夹
  • 文件/文件夹重命名
  • 文件写入

首先,我们需要先设计出文件在内存中进行管理的数据结构定义

// 定义文件的类型
export const enum FileType {
  File,
  Directory,
}

// 文件的结构定义
export interface IFileSystemItem {
  filename: string;  	/* 文件名 */
  type: FileType.File; 	/* 文件类型 */
  code: string;			/* 文件的代码 */
  ext: string;			/* 文件的扩展名 */
  fullPath: string;		/* 文件的完整路径 */
  status: number;		/* 文件当前的状态: 用于记录当前对文件的操作 */
  cacheBuffer: string | null  /** 文件内容缓冲区 */;
  language?: string;	/* 代码语言 */
  readonly?: boolean;	/* 文件是否只读 */
  visible?: boolean;	/* 文件是否在文件树中显示 */
}

// 目录的结构定义
export interface IDirectoryItem extends Record<string, unknown> {
  filename: string; 			/* 文件名 */
  type: FileType.Directory;		/* 文件类型 */
  fullPath: string;				/* 文件完整路径 */
  status: number;				/* 文件夹当前状态 */
  readonly?: boolean;			/* 文件夹是否只读 */
  visible?: boolean;			/* 文件夹是否在文件树中可见 */
  children: (IFileSystemItem | IDirectoryItem)[];	/* 文件夹下的子文件 */
}

定义好文件系统在内存中的存储结构后,我们还需要定义文件系统的响应式 State 中的数据结构

export type FileSystemState = {
  /* 文件树 - 单根文件夹 */
  files: IDirectoryItem;
  /* 文件Map映射,方便快速的根据文件路径查找文件 */
  fileMap: Map<string, IFileSystemItem | IDirectoryItem>;
};

对于文件的操作,我们将通过文件的 status 字段进行记录,比如文件编辑、文件重命名等;那如何通过一个字段来记录多种状态呢? 这里我们采用二进制位Mask来处理,首先我们先定义几个基础的文件操作:

export const enum FileOperation {
  Editing = 0b00000001,
  Rename = 0b00000010,
  Delete = 0b00000100,
  Move = 0b00001000,
  Create = 0b00010000,
}

关于如何通过二进制位Mask来记录不同的状态,我们将在下篇文章中具体实现文件系统进行介绍

完成以上步骤之后,现在我们可以开始定义文件系统的接口描述了,文件系统Store 是一个继承自响应式基类的文件管理子类,处理响应式文件State 数据之外,还有相关的文件操作逻辑:

export interface FileSystemProvider {
  /* 响应式的文件数据 */
  state: FileSystemState;
	
  /**
   * 创建文件
   * @param path 文件路径 uri
   * @param content 文件内容
   * @param readonly 是否只读
   * @param visible 是否可见
   */
  createFile(
    path: Uri,
    content: string,
    readonly?: boolean,
    visible?: boolean
  ): IFileSystemItem;

  /**
   * 创建目录
   * @param path 目录 Uri
   * @param readonly 是否只读
   * @param visible 是否可见
   */
  createDirectory(
    path: Uri,
    readonly?: boolean,
    visible?: boolean
  ): IDirectoryItem;

  /**
   * 读取文件内容
   * @param path 文件路径 uri
   */
  readFile(path: Uri | string): IFileSystemItem | IDirectoryItem | null;

  /**
   * 写入文件数据
   * @param path 文件路径 uri
   * @param content 文件内容
   * @returns 文件变更状态数据
   */
  writeFile(
    path: Uri | string,
    content: string,
    isBuffer?: boolean
  ): ChangeFileState | null;
	
  /**
   * 删除文件或目录
   * @param file 文件对象
   * @returns 文件变更状态数据
   */
  delete(file: IFileSystemItem | IDirectoryItem): ChangeFileState | null;

  /**
   * 文件重命名
   * @param file 文件对象
   * @param newName 文件名
   * @returns 文件变更状态数据
   */
  renameFile(file: IFileSystemItem, newName: string): ChangeFileState;

  /**
   * 文件夹重命名
   * @param folder 文件对象
   * @param newName 文件名
   * @returns 文件变更状态数据
   */
  renameFolder(folder: IDirectoryItem, newName: string): ChangeFileState[];

  /**
   * 移动文件
   * @param sourcePath 源路径
   * @param targetPath 目标路径
   * @returns 文件变更状态数据数组
   */
  moveFile: (
    sourcePath: Uri | string,
    targetPath: Uri | string
  ) => ChangeFileState[] | null;

  /**
   * 为文件对象添加操作
   * @param file 文件对象
   * @param operator 操作
   */
  addOperator: (
    file: IFileSystemItem | IDirectoryItem,
    operator: FileOperation
  ) => void;

  /**
   * 为文件对象移除操作
   * @param file 文件对象
   * @param operator 操作
   */
  removeOperator: (
    file: IFileSystemItem | IDirectoryItem,
    operator: FileOperation
  ) => void;
}

小结

这一章我们正式开始组件库的开发,组件的开发我认为最重要的不是组件如何渲染,而是数据如何维护和管理;
从这章开始我们介绍的是整个编辑器组件的核心:文件系统; 我们将按照面向接口编程的方式,逐步设计和实现文件系统的管理和操作。这一章节我们通过TS类型定义设计实现了文件系统相关的接口定义,大家也可以根据目前文件系统的接口定义,尝试实现文件系统管理类。

如果大家在开发过程中有任何的问题欢迎下方留言评论,我将尽快为大家解答;加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值