https://github.com/ifrozenwhale/file_manager
文件管理器
各模块功能实现
功能实现
- 界面跳转:
- 后退,逐级返回到父级目录。
- 前进,按照后退的顺序依次进入子目录。
- 当前目录路径显示,输入目录地址进行跳转。
- 界面显示:
- 文件目录树显示(只显示文件夹)。
- 文件列表显示(只显示当前目录下的文件夹和文件),带有系统图标。
- 点击文件树中的结点,在文件列表同步显示。
- 选择与打开
- 支持多选,选中文件高亮显示,点击空白区域取消选中。
- 单击文件夹进入,单击文件打开应用。
- 右键选中文件
- 批量复制,包括所有子目录和文件。
- 批量压缩,格式为zip,将多个文件压缩成一个,自定义命名。
- 单文件加密,自定义加密密钥。
- 右键空白区域
- 创建文件夹,自定义命名;
- 批量粘贴,粘贴的目录不能是源文件目录的子目录;
- 批量解压,解压到当前目录下。
- 单文件解密,输入加密密钥,若密钥不正确,加密后的文件仍无法打开。
算法设计
主要是FileModel
的实现
数据记录
- 由
List<File> defaultListModel
和File currentFile
负责记录当前目录和目录下的文件、文件夹。
初始化
initRoots
方法,将磁盘目录,如C:\
,D:\
,E:\
添加进文件列表。
文件更新
updateModels(File file)
方法,将当前文件设为file
,并将其当前目录层级下的文件(夹)添加进文件列表。
前进和后退
- 由
redoStack
负责记录操作路径,undo时,得到父级目录下文件和文件夹,更新文件列表,并将文件压入redoStack
。 - redo时,弹出栈顶文件,更新当前文件列表。
- 细节,如果父级为
null
,说明当前是磁盘根目录,如D:\
,则调用初始化方法initRoots
。
文件复制
- 由
copySources
负责存储粘贴板中的文件。 - 选中文件后,加入到
copySources
中。 - 粘贴时,判断是文件,还是文件夹
- 如果是文件,则进行文件复制。
- 如果是文件夹,递归调用。
- 异常处理,粘贴的目录不能是源目录的子目录,由
isParent
进行判断。
创建和删除
- 如果不存在,则创建。
- 递归删除,由
deleteHelp
负责递归,如果删除的是文件夹,就递归调用,最终删除根文件。 - 对选中的文件遍历执行,批量删除。
压缩和解压
- 对于文件,直接压缩。
- 对于文件夹,递归压缩。
文件加密和解密
- 对文件读取字节内容,与密钥进行简单的异或加密。
- 加密后得到新文件,删除原始文件,并将新文件重命名为原文件。(也可以不删除,防止出问题,重要文件)
- 解密的时候,与加密过程相同,输入密钥,读取文件,异或解密。
取消选中
重写
locationToIndex
函数,判断点击的位置是否有效javaint index = super.locationToIndex(location); if (index != -1 && !getCellBounds(index, index).contains(location)) return -1;
样式渲染
- 实现
FileListCellRenderer
类继承DefaultListCellRenderer
- 设置图标,设置显示信息,磁盘根目录使用
getPath()
,其他目录使用getName()
。 - 选中设置颜色,取消选中恢复之前的颜色。
文件树展开
- 实现
TreeSelectionListener
接口,采用延迟加载,即每次点击展开时再加载目录文件。
软件调试分析
执行过程
启动
App
类的main
函数在
FileController
初始化的时候,完成对数据成员的初始化,包括添加事件监听,更新初始视图。javapublic FileController(App app, FileModel fileModel, FileTreeModel treeModel) { this.fileDisplay = app.getFileDisplay(); this.app = app; this.fileModel = fileModel; this.filesTree = app.getFilesTree(); this.treeModel = treeModel; // 添加事件监听 fileDisplay.addCopyListener(new CopyListener()); fileDisplay.addCreateListener(new CreateFileListener()); fileDisplay.addPasteListener(new PasteListener()); fileDisplay.addUnzipListener(new UnZipListener()); fileDisplay.addZipListener(new ZipListener()); fileDisplay.addDeleteListener(new DeleteListener()); fileDisplay.addMyMouseListener(new FileClickListener()); fileDisplay.addEncodeListener(new EncodeListener()); fileDisplay.addDecodeListener(new DecodeListener()); app.addUndoListener(new UndoListener()); app.addRedoListener(new RedoListener()); app.addGoListener(new GoListener()); filesTree.addTreeSelectionListener(new FileTreeSelListener()); filesTree.setRootVisible(false); // 初始化主视图 fileDisplay.updateView(fileModel.getDefaultListModel()); }
监听到事件发生,调用
model
和view
进行逻辑实现并更新视图。例如,展开文件目录树时,需要对三部分视图进行更新(文件树,文件列表,url地址栏)javaclass FileTreeSelListener implements TreeSelectionListener { @Override public void valueChanged(TreeSelectionEvent e) { File file = filesTree.getCurrentFile(); // 得到点击的文件结点 // 加载目录树 filesTree.loadingTree((DefaultMutableTreeNode) filesTree.getLastSelectedPathComponent(), treeModel.getFiles(file)); // 更新文件数据模型 fileModel.updateModels(file); // 更新文件列表视图 fileDisplay.updateView(fileModel.getDefaultListModel()); // 更新url地址显示 String url = fileModel.getUrl(); app.updateUrl(url); } }
再如,undo操作时,
model
进行undo,更新数据,然后视图更新javaclass UndoListener implements ActionListener{ @Override public void actionPerformed(ActionEvent e) { fileModel.undo(); // 数据模型更新 fileDisplay.updateView(fileModel.getDefaultListModel()); // 列表视图更新 String url = fileModel.getUrl(); app.updateUrl(url); // url地址栏更新 } }
界面展示
主界面
- 上侧可以后撤、前进,url地址栏显示
- 左侧目录树展开,并同步更新右侧文件列表
文件及文件夹拷贝
右键粘贴,将子目录下所有文件(夹)粘贴