移动文件是最常用的操作之一。在计算机中移动文件有两种形式:第一种是复制,就是在目标位置创建一个与源文件一模一样的新文件,最终得到两个文件;第二种是剪切,就是将源文件转移到新位置,最终只有一个文件。
文件批处理助手中的批量移动功能允许用户定制移动任务,用户可以将多个位于不同位置的文件或文件夹放到任务列表中,然后统一将它们移动到目标位置。在此过程中,用户可以选择复制或剪切两种移动方式。
批量移动功能面板的效果如图2.2所示。
图2.2 批量移动功能面板的效果
MoveBatchPanel类是项目中的批量移动功能面板类,它继承自JPanel面板类。MoveBatchPanel面板已在JTabbedPaneFactory功能面板工厂类中完成了登记,因此可以直接在主窗体中显示。下面分别介绍MoveBatchPanel类中的属性和主要方法。
(1)MoveBatchPanel类属性包括界面上方添加文件或文件夹的按钮、中央显示的表格和下方的功能按钮区。其中:taskList是一个键值对类型的属性,用于记录任务列表,键的泛型使用File类型,表示待移动文件;值的泛型使用Integer类型,表示文件所属的子文件层级,例如根目录的层级为0,根目录下的子文件夹层级为1,如果子文件夹中还有子文件夹,那么第二层子文件夹的层级就为2。记录文件及其对应的层级可以确保在程序复制文件夹时,原始文件夹中所有子文件及子文件夹的目录结构得到保留。
属性代码如下:
(2)批量移动功能面板采用SpringLayout弹性布局,确保每个组件的边界与面板的边界保持一定的距离。当面板大小发生变化时,组件的大小也会相应地进行调整。init()方法用于初始化面板中的所有组件,该方法的代码如下:
(3)“移动到”按钮用于指定移动目标文件夹。当用户单击该按钮时,会弹出文件选择器。如果用户选择某个文件夹,该文件夹的详细地址将显示在文本框中。
“移动到”按钮添加动作事件的代码如下:
(4)“添加文件”按钮用于向任务列表中添加单个文件。单击该按钮后,弹出的文件选择器仅允许用户选择文件,而不可以选择文件夹。用户选择某个文件之后,系统会调用recordFiles()方法将该文件记录到任务列表中,并将其显示在窗体表格中。每个选中的文件的子文件夹层级都被为0。
“添加文件”按钮添加动作事件的代码如下:
(5)“添加文件夹”按钮用于将某个文件夹下的所有子文件和子文件夹都添加到任务列表中。单击该按钮后,弹出的文件选择器仅允许用户选择文件夹,而不会显示具体文件。用户选择某个文件夹之后,系统会调用recordFiles()方法将文件夹中的所有文件按照它们的层级记录到任务列表中。随后这些文件和文件夹都会显示在窗体表格中。
为“添加文件夹”按钮添加动作事件的代码如下:
(6)recordFiles()方法用于记录文件数据,该方法接收两个参数:第一个参数dir表示要记录的文件对象,第二个参数tab表示文件的子文件层级。例如:如果dir是根目录,则传入0;如果dir是选中文件的子文件,则传入1;以此类推,更深层的子文件就传入2、3、4等。recordFiles()方法使用递归方式获取某个文件夹下的所有文件及其子文件夹下的所有文件,确保在用户移动文件夹时,该文件夹下的所有文件及文件夹都可以被添加到任务列表中。
recordFiles()方法将所有待移动的文件都保存到taskList任务列表中,同时会将这些文件显示在窗体的列表中。此外,它还将列表中的第二列“完成情况”统一设置为“准备中”。
recordFiles()方法的代码如下:
(7)“移动文件”按钮和“复制文件”按钮都使用相同的触发方法moveButtonAction(),但该方法通过不同的参数来控制在执行移动文件操作或者复制文件操作后,是否删除源文件。
为“移动文件”按钮添加动作事件的代码如下:
为“复制文件”按钮添加动作事件的代码如下:
(8)“移动文件”按钮和“复制文件”按钮触发的moveButtonAction()方法接收一个名为deleteFile的参数,该参数表示是否删除源文件。在该方法中,首先会校验用户是否已经选择了目的地文件夹。如果用户没有选择目标文件夹或者目标文件夹不可用,则只弹出提示,不进行任何移动操作;如果用户已经选择了目标文件夹,则会创建一个Thread线程对象,其构造方法使用实现了Runnable接口的Lambda表达式作为参数,在该Lambda表达式中遍历taskList任务列表中所有的文件,取出每个文件对应的文件层级。如果遍历出的文件具有多层子文件夹结构,则在目标文件夹中创建这些子文件夹。接着,使用moveFile()方法移动源文件。如果移动成功,还会从窗体表格中删除对应的行记录。最后,启动线程。
把移动文件操作放到线程中执行,可以避免移动文件时阻塞窗体线程,这样用户可以直观地看到窗体表格中的数据不断变化。当表格中第二列文字从“准备中”变成“完成”时,表示该行记录的文件已完成移动或复制操作。
moveButtonAction()方法的代码如下:
(9)移动文件时调用的moveFile()方法有三个参数:第一个参数file表示移动的源文件,第二个参数target表示移动后的文件,第三个参数delete表示移动后是否删除源文件。该方法最后会返回boolean值,表示移动操作是否成功。
该方法使用文件流和缓冲流读取和写入文件数据,字节缓冲区采用1024字节。这种写法可以提高程序的执行效率。
如果第三个参数delete传入true,则会在移动之后删除源文件。
moveFile()方法的代码如下:
(10)用户在单击“移除选中文件”按钮后,程序将判断是否有选中的行。如果有选中的行,则程序将从任务列表中删除对应的任务。
说明
当任务列表中有多行任务被选中时,务必使用循环从下往上删除对应的任务。这是因为如果从上往下删除对应的任务,下面的任务会自动向上填充,从而改变之前任务的索引位置,这可能导致循环变量错误或溢出。
为“移除选中文件”按钮添加动作事件的代码如下:
同样类型的文件可能因为来源不同而具有不同的命名格式,很多文件的命名非常长,并且可能会带有前缀或后缀。例如,不同手机拍摄的图片自动生成名字各不相同,而使用不同截图软件截取的图片名称也不一样。
用户如果想手动为这些文件更名,则会浪费大量时间。批量重命名功能模块就是为了解决此问题而设计的。用户可以在程序中指定命名模板,模板会自动将“#”字符更换为数字,用户只需设置好起始数字即可。例如,使用“照片#”模板,所有文件将依次被更名为“照片1”“照片2”“照片3”等。
批量重命名功能面板的效果如图2.3所示。
图2.3 批量重命名功能面板的效果图
RenameBatchPanel类是项目中用于实现批量重命名功能的面板类,它继承自JPanel面板类。RenameBatchPanel面板已在PanelFactory面板工厂类中完成注册,因此可以在主窗体中进行显示。下面分别介绍RenameBatchPanel类中的属性和主要方法。
(1)RenameBatchPanel类属性包括面板中使用的组件,代码如下:
(2)单击“浏览”按钮会弹出一个文件选择器,用于指定被批量更名的文件夹。更名操作会更改文件夹下的所有文件名,但不会更改子文件夹及子文件夹中文件的名字。
为“浏览”按钮添加动作事件的代码如下:
(3)批量更名面板的核心功能代码主要集中在“开始”按钮所触发的事件处理中。用户单击“开始”按钮后,首先,程序会检查用户是否已选择了一个文件夹。如果用户没有选择任何文件夹,或者所选的文件夹是不可用状态,程序将立即停止操作。接下来,程序会获取命名模板中的字符串,分析字符串中“#”字符的数量,并将所有的“#”字符替换为对应的格式化标识符。例如,“###”会被替换为“%03d”,其中“%”是格式化标识前缀,“0”表示如果数字长度不足,将在其左侧填充0,“3”表示数字的最小长度为三位数,“d”表示格式化传入的数字为整数。在获取了格式化后的命名模板之后,程序将读取用户设置的起始数字(默认为0)和文件后缀名。如果文件后缀名文本框为空,程序将使用源文件的后缀名。最后,程序会遍历用户选定的文件夹下的所有文件,并使用renameTo()方法对这些文件进行重命名。在重命名过程中,“#”字符所表示的数字将递增,并在窗体的表格中显示更名结果。
为“开始”按钮添加动作事件监听器的代码如下:
搜索文本是对单一文件使用的功能。用户可以设置搜索关键字和读取文件的格式,程序会扫描文件中所有的文本。一旦在文件中发现关键字文本,程序将在界面中显示所在行数和该行文本。该功能适合从文本巨大的文件中检索关键信息。该功能仅能读取文本形式的文件,不能读取如Word、Excel等特殊文本格式的文件。
搜索文本功能面板的效果如图2.4所示。
图2.4 搜索文本功能面板的效果
SearchFileTextPanel类是项目中的搜索文本功能面板类,它继承自JPanel面板类。SearchFileTextPanel面板已在PanelFactory面板工厂类中完成注册,因此可以在主窗体中进行显示。下面分别介绍SearchFileTextPanel类中的属性和主要方法。
(1)SearchFileTextPanel类属性包括面板中使用的组件,代码如下:
(2)单击“选择文件”按钮后,会打开文件选择器,用户可以通过该选择器选择要读取的文件。用户单击文件选择器上的“打开”按钮后,所选文件的完整路径将被填写到文本框中。
为“选择文件”按钮添加动作事件监听器的代码如下:
(3)搜索文本功能的核心代码主要集中在“开始查找”按钮上。当用户单击“开始查找”按钮时,首先,程序会校验用户是否已选择了要读取的文件,如果用户没有选任何文件,或者文件是不可用状态,程序将直接停止操作;然后,程序会获取并记录用户输入的关键字和选择的字符编码。最后,程序使用FileInputStream文件字节输入流来获取读取文件,使用InputStreamReader将字节流转换为字符流,并在转换过程中指定字符编码,使用BufferedReader缓冲字符流逐行读取文件中的内容。在读取过程中,程序使用字符串的contains()方法判断读取的一行文字中是否包含关键字,如果包含关键字,则将其显示在窗体的文本域中。
为“开始查找”按钮添加动作事件监听器的代码如下: