Java 文件夹备份

前段时间公司要求给服务器上一个存放数据的文件弄一个备份,在网上找了很多软件,要么就是收费要么就是service系统不能用,干脆自己写一个,慢点就慢点吧。

准备:

开发环境:
Idea
jdk1.8
maven

在Idea中创建一个springboot的项目,我这边有需求mvc所以导入mvc的包;

pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gjdw</groupId>
    <artifactId>syncfolder</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>syncfolder</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

写一个实体类作为参数:

package com.gjdw.syncfolder.entity;

public class SyncFolder {

    private Long id;

    // 需要备份的文件夹路径
    private String oldFolderPath;

    // 备份到的文件夹
    private String saveFolderPath;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getOldFolderPath() {
        return oldFolderPath;
    }

    public void setOldFolderPath(String oldFolderPath) {
        this.oldFolderPath = oldFolderPath;
    }

    public String getSaveFolderPath() {
        return saveFolderPath;
    }

    public void setSaveFolderPath(String saveFolderPath) {
        this.saveFolderPath = saveFolderPath;
    }
}

编写工具链用来备份文件:

package com.gjdw.syncfolder.util;

import com.gjdw.syncfolder.entity.SyncFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;

/**
 * @author Administrator
 */
public class FileSave {
    // 将文件备份到的文件夹
    private String savePath;
    // 需要备份的文件夹
    private String filePath;
    // 复制的文件总数
    private int fileNum = 0;
    // 错误的文件总数
    private int errorNum = 0;
    // 记录所有线程
    private List<Thread> threads = new ArrayList<Thread>();

    private static final transient Logger log = LoggerFactory.getLogger(FileSave.class);

    // method整合
    public int copy(SyncFolder syncFolder) throws IOException, InterruptedException {
        Vector<Thread> vector = new Vector<Thread>();
        System.out.println();
        String path = syncFolder.getOldFolderPath();
        filePath = path;
        savePath = syncFolder.getSaveFolderPath();
        File file = new File(path);
        if(file.isDirectory()){
            File saveFile = new File(savePath);
            if(!saveFile.isDirectory()){
                log.info(savePath+"保存文件夹不存在!!!");
                return -1;
            }
            log.info("开始备份"+path+"文件夹");
            fileWritePath(file);

            log.info("所有线程数: "+String.valueOf(threads.size()));
            for (Thread t:threads) {
                t.join();
                System.out.println("等待:"+t.toString());
            }
            log.info("本次备份文件:" + fileNum + "个");
            return fileNum;
        }else{
            log.info(path+"文件夹不存在!!!");
            return -1;
        }

    }

    // 1、获取该文件或文件夹下所有文件路径
    // 2、如果是文件则备份到指定位置
    // 3、如果是文件夹则循环遍历
    public void fileWritePath(File source) throws IOException {
        // 如果是文件夹迭代
        if (source.isDirectory()) {
            if (source.listFiles() != null && source.listFiles().length != 0)
                for (File file : source.listFiles())
                    fileWritePath(file);
        }
        // 如果是文件,且不是该文件自身
        if (source.isFile()
                && source.toString().indexOf("FileSave.class") == -1) {
            //copyFile(source);
            Thread thread = new Thread() {
                @Override
                public void run() {
                    try {
                        //对指定的文件进行复制操作
                        String newPath = savePath
                                + source.getAbsolutePath().toString();
                        newPath = newPath.replace(new String(savePath + filePath.substring(3)).replace("/", "\\"), savePath);
                        newPath = newPath.replace(filePath, "");
                        //获取新文件所在路径
                        File oldFile = new File(newPath);
                        // 如果文件存在
                        if (oldFile.exists()) {
                            System.out.println(oldFile.getPath()+"文件存在");
                            System.out.println();
                        } else {
                            // 如果文件不存在
                            // 先创建该文件所在的文件夹
                            File file = new File(oldFile.toString().substring(0,
                                    (newPath.lastIndexOf("\\"))));
                            // 同时创建多层文件夹
                            file.mkdirs();

                            System.out.println(oldFile.getPath()+"文件备份完成");
                            // 进行文件复制操作
                            FileInputStream infile = new FileInputStream(source.toString());
                            FileOutputStream outfile = new FileOutputStream(oldFile.toString(), true);
                            byte[] bb = new byte[1024];
                            int lenth = 0;
                            while ((lenth = infile.read(bb)) != -1) {
                                outfile.write(bb, 0, lenth);
                            }
                            outfile.flush();
                            outfile.close();
                            infile.close();
                            fileNum++;
                            System.out.println(fileNum);
                            // 对备份的文件数进行统计
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };
            thread.start();
            threads.add(thread);
        }
    }

    // 字节流文件复制
//    public void copy_sy4(String oldFile, String newFile) throws IOException {
//        FileInputStream infile = new FileInputStream(oldFile);
//        FileOutputStream outfile = new FileOutputStream(newFile, true);
//        byte[] bb = new byte[1024];
//        int lenth = 0;
//        while ((lenth = infile.read(bb)) != -1) {
//            outfile.write(bb, 0, lenth);
//        }
//        outfile.flush();
//        outfile.close();
//        infile.close();
//    }



    // 文件重名
    // 只留一个备份文件
    public void fileNewName(File file) {
        String fileSuffix = new SimpleDateFormat("HH-mm-ss").format(new Date());
        file.renameTo(new File(file.toString() + "~" + fileSuffix));
    }
}

这里我们用到了多线程,可以提高备份的失效性,实测1g的数据26000个左右的文件在顺序执行的情况下需要30秒-40每秒之间,使用多线程只需7秒,具体情况看机器配置来决定,而且主线程等待备份数据的线程用的方法不是很好。

使用Scheduled用来做定时任务

package com.gjdw.syncfolder.scheduled;

import com.gjdw.syncfolder.entity.SyncFolder;
import com.gjdw.syncfolder.util.FileSave;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.scheduling.annotation.Scheduled;

import java.io.IOException;

/**
 * 定时任务类,用来执行定时任务
 * */
@Component
public class FileScheduled {

    private static final transient Logger log = LoggerFactory.getLogger(FileScheduled.class);

    @Scheduled(cron = "0 00 21 * * ?")
    public void fixTimeExecution() {
        log.info("*****************开始执行邮件定时任务********************");
        FileSave f = new FileSave();
        int fieNum = 0;
        try {
            SyncFolder syncFolder = new SyncFolder();
            syncFolder.setOldFolderPath("D:\\kjzx");
            syncFolder.setSaveFolderPath("H:\\kjzx_backup");
            fieNum =  f.copy(syncFolder);
            log.info("*****************定时任务完成,此次备份文件"+fieNum+"个********************");
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            log.info("*****************定时任务失败***********************");
        }
    }
}

这样一个基本的文件夹备份程序基本写完了,但是注意这样只能执行定时任务,需要手动触发和多任务备份,需要在写上页面等代码,这里就不一一讲述,希望对你有所帮助。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值