目錄
一、前言
程序經常會出現功能更新,bug修復的情況,這種情況下,怎麼實現軟件升級呢?本篇博客將介紹一種實現思路,大家可以借鑑借鑑,有錯誤的地方還望提出指正。後端是java實現的。
二、實現思路
1、獲取到舊版本和新版本的所有文件列表,根據新版本的文件名去舊版本中找,這種情況下會出現兩種情況:
第一種:舊版本中找到了對應的文件,這時候計算一下兩個文件的md5值,如果md5值一樣,說明文件沒有更新,不一樣,則說明文件更新了。
第二種:舊版本中沒有找到對應的文件,這個時候說明這個文件是新增的文件。
2、服務器上新建一個新版本目錄、舊版本目錄和更新文件目錄,每次有更新,把所有文件上傳到新版本目錄中。點擊“更新比對”按鈕,後臺執行比較程序,獲取到所有新版本目錄中的文件,和舊版本目錄中的文件進行比較,把有更新的文件和新增的文件存儲一份到更新文件目錄中。最後把新版本目錄中的文件全部覆蓋掉舊版本目錄中的文件,使新舊版本文件保持一致。客戶端更新只需要下載更新文件目錄中的文件覆蓋掉客戶端的文件即可。
三、準備工作
1、在服務器上新建一個目錄來存放我們軟件的文件,如:新建一個“software”目錄。在“software”目錄下面新建三個目錄,如:“new”、“old”、“update”。“new”目錄用於存放新版本的文件。“old”用於存放舊版本的文件。“update”用於存放更新或者新增的文件。
2、每次軟件有升級或者更新,把文件上傳到“new”目錄下面。
四、本地測試模擬效果
1、未執行程序代碼之前的效果圖
1、準備3個文件夾
2、新版本的文件目錄如下
3、舊版本的目錄如下
4、更新版本目錄如下
2、執行程序代碼之後的效果圖
程序執行結束之後,可以發現,有變更的文件已經移動到了“update”目錄下面,並且“new”和“old”目錄下面的文件也同步了。客戶端下載更新只需要下載“update”目錄下面的文件即可。下次有新的更新同理,只需要把程序的文件上傳到“new”目錄下面,執行一遍程序,即可完成文件的更新。
五、測試程序代碼
代碼註釋都寫的很清楚,可以根據自己的需求優化,集成進自己的系統中。
package top.zywork.test;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.*;
import java.util.ArrayList;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* 測試系統文件更新
* @author Red
*/
public class SysUpdateTest {
/**
* 獲取一個文件夾下的所有文件全路徑
* @param path 文件夾路徑
* @param listFileName 存儲文件名
*
*/
public static void getAllFileName(String path, ArrayList<String> listFileName) {
File file = new File(path);
File[] files = file.listFiles();
String[] names = file.list();
if (names != null) {
String[] completNames = new String[names.length];
for (int i = 0; i < names.length; i++) {
completNames[i] = path + names[i];
}
listFileName.addAll(Arrays.asList(completNames));
}
for (File a : files) {
//如果文件夾下有子文件夾,獲取子文件夾下的所有文件全路徑。
if (a.isDirectory()) {
getAllFileName(a.getAbsolutePath() + "\\", listFileName);
}
}
}
/**
* 重命名文件
* @param filePath 重命名後文件的目標目錄
* @param fileName 重命名前的完整文件路徑
* @return
*/
public static void renameFile(String filePath, String fileName) {
SimpleDateFormat fmdate = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String oldFileName = fileName;
File oldFile = new File(oldFileName);
String newFileName = filePath+File.separator+fmdate.format(new Date())+"."+fileName.split("\\.")[1];
File newFile = new File(newFileName);
if (oldFile.exists() && oldFile.isFile()) {
oldFile.renameTo(newFile);
}
}
/**
* 刪除指定文件夾下面的文件及目錄
* @param floder 需要刪除文件夾目錄
* @param deleteFloder 是否需要刪除文件夾,true=需要、false=不需要
*/
public static void deleteFolder(File floder, boolean deleteFloder) {
File[] files = floder.listFiles();
if (null != files) {
for (File f :files) {
// 如果是文件夾,遞歸調用刪除文件夾的方法
if (f.isDirectory()) {
deleteFolder(f, true);
} else {
f.delete();
}
}
}
if (deleteFloder) {
// 刪除文件夾目錄
floder.delete();
}
}
/**
* 刪除指定的目錄,該目錄下的所有文件和目錄也會刪除
* @param srcDir 需要刪除的目錄
*/
public static void deleteFiles(String srcDir, boolean deleteFloder) {
File file = new File(srcDir);
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f : files) {
if (f.isDirectory()) {
deleteFiles(f.getAbsolutePath(), true);
} else {
f.delete();
}
}
}
}
if (deleteFloder) {
// 需要刪除文件目錄
file.delete();
}
}
/**
* 獲取指定路徑的文件的目錄部分
* @param filePath 文件路徑
* @return
*/
public static String getDirs(String filePath) {
return filePath.substring(0, filePath.lastIndexOf(File.separator));
}
/**
* 根據指定的路徑,如果沒有此路徑則創建並返回絕對路徑,否則直接返回絕對路徑
* @param dirs 多級目錄
* @return
*/
public static String mkdirs(String dirs) {
File path = new File(dirs);
if (!path.exists()) {
path.mkdirs();
}
return path.getAbsolutePath();
}
/**
* 根據完整的路徑創建新文件
* @param filePath
*/
public static boolean createNewFile(String filePath) {
File file = new File(filePath);
if (!file.exists()) {
String dirs = getDirs(filePath);
mkdirs(dirs);
try {
return file.createNewFile();
} catch (IOException e) {
System.err.println("create new file error: " + e.getMessage());
return false;
}
}
return true;
}
/**
* 拷貝文件,支持任意文件類型
* @param srcPath
* @param destPath
*/
public static void copyFile(String srcPath, String destPath) {
File srcFile = new File(srcPath);
if (srcFile.exists()) {
if (createNewFile(destPath)) {
try (InputStream in = new FileInputStream(srcPath);
FileOutputStream out = new FileOutputStream(destPath)) {
byte[] bytes = new byte[1024];
int length;
while ((length = in.read(bytes)) != -1) {
out.write(bytes, 0, length);
}
} catch (IOException e) {
System.err.println("copyFile error: " + e.getMessage());
}
}
}
}
public static void handleFileUpdate(String basePath) throws Exception {
ArrayList<String> newFileList = new ArrayList<String>();
getAllFileName(basePath + "new" + File.separator, newFileList);
ArrayList<String> oldFileList = new ArrayList<String>();
getAllFileName(basePath + "old" + File.separator, oldFileList);
if (newFileList.isEmpty()) {
System.out.println("新版文件爲空");
return;
}
if (oldFileList.isEmpty()) {
System.out.println("舊版文件爲空");
return;
}
ArrayList<String> updateFileList = new ArrayList<>();
System.out.println("開始更新文件:新版本文件總數:" + newFileList.size() + ",舊版本文件總數:" + oldFileList.size());
for (String newFilePath : newFileList) {
if (new File(newFilePath).isDirectory()) {
// 是文件夾,跳過循環
continue;
}
boolean updateFlag = false;
String newFileMd5 = DigestUtils.md5Hex(new FileInputStream(newFilePath));
for (String oldFilePath : oldFileList) {
if (new File(oldFilePath).isDirectory()) {
// 是文件夾,跳過循環
continue;
}
String oldFileMd5 = DigestUtils.md5Hex(new FileInputStream(oldFilePath));
// 暫時把新版文件名路徑換成和舊版文件名路徑一樣的,用於判斷文件是否存在舊版
String tempNewFilePath = newFilePath.replace(File.separator + "new" + File.separator, File.separator + "old" + File.separator);
if (oldFileList.contains(tempNewFilePath)) {
// 當前文件存在舊版本中
if (oldFilePath.equals(tempNewFilePath)) {
// 說明文件存在,判斷這兩個文件的md5值是否一樣
if (!newFileMd5.equals(oldFileMd5)) {
// md5值不一樣,說明文件有更新
updateFlag = true;
oldFileList.remove(oldFilePath);
break;
}
}
} else {
// 當前文件不存在舊版本中,是新增的文件
updateFlag = true;
break;
}
}
if (updateFlag) {
// 當前文件有更新或者是新增的文件
updateFileList.add(newFilePath);
}
}
if (updateFileList.isEmpty()) {
System.out.println("程序結束,沒有需要更新的文件");
return;
}
System.out.println("開始處理更新文件:更新文件總數:" + updateFileList.size());
// 刪除更新版本目錄下面的所有文件
deleteFiles(basePath + "update" + File.separator, false);
for (String updateFilePath : updateFileList) {
String tempUpdateFilePath = updateFilePath.replace(File.separator + "new" + File.separator, File.separator + "update" + File.separator);
// 將需要更新的文件複製到更新版本中
copyFile(updateFilePath, tempUpdateFilePath);
}
System.out.println("更新文件處理完成,開始把新版本的文件複製到舊版本中");
// 同時把新版本的文件複製到舊版本中
deleteFiles(basePath + "old" + File.separator, false);
for (String newFilePath : newFileList) {
if (new File(newFilePath).isDirectory()) {
// 是文件夾,跳過循環
continue;
}
String tempOldFilePath = newFilePath.replace(File.separator + "new" + File.separator, File.separator + "old" + File.separator);
copyFile(newFilePath, tempOldFilePath);
}
System.out.println("程序處理結束");
}
public static void main(String[] args) throws Exception {
handleFileUpdate("C:\\Users\\Wangchenchen\\Desktop\\software\\");
}
}
所有代碼都已經在上面了,如果你覺得對你有幫助,不妨給博主點個贊吧^_^
六、結尾
更多精彩好文請移步:http://wjhsmart.vip