日誌的轉儲和壓縮是非常關鍵的,它不僅可以減少硬碟空間佔用,主要還可以在發生故障時根據日誌定位出故障原因。下面來看看golang和java的檔案轉儲實現。
go語言:
用到了filepath包下的Walk方法,具體說明可以參看曆史文章:
go語言path/filepath包之Walk源碼解析
package mainimport ( "fmt" "os" "io" "archive/zip" "path/filepath" "time" "log")func main() { logFile := "D:/tmp/successLog/logs/root.log" backFile := "D:/tmp/successLog/logs/root_" + time.Now().Format("20060102150405") + ".zip" err := zipFile(logFile, backFile) if err != nil { log.Println(fmt.Sprintf("zip file %s to %s error : %v", logFile, backFile, err)) return } else { os.Remove(logFile) } //轉儲後建立新檔案 //createFile() //修改檔案許可權 //os.Chmod(backfile, 0400) //刪除備份檔案 //deleteOldBackfiles(dir)}func zipFile(source, target string) error { zipFile, err := os.OpenFile(target, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0440) if err != nil { log.Println(err) return err } defer zipFile.Close() archive := zip.NewWriter(zipFile) defer archive.Close() return filepath.Walk(source, func(path string, info os.FileInfo, err error) error { if err != nil { return err } header, err := zip.FileInfoHeader(info) if err != nil { return err } if !info.IsDir() { header.Method = zip.Deflate } header.SetModTime(time.Now().UTC()) header.Name = path writer, err := archive.CreateHeader(header) if err != nil { return err } if info.IsDir() { return nil } file, err := os.Open(path) if err != nil { return err } defer file.Close() _, err = io.Copy(writer, file) return err })}
go壓縮結果
java版:
說明見注釋。
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.*;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.zip.CRC32;import java.util.zip.CheckedOutputStream;import java.util.zip.ZipEntry;import java.util.zip.ZipOutputStream;/*** @program: website* @description: 轉儲壓縮檔* @author: smallsoup* @create: 2018-08-12 17:58**/public class ZipFile { private static final Logger LOGGER = LoggerFactory.getLogger(ZipFile.class); /** * 格式檔案名格式 */ private static final String AUDIT_LOG_FORMAT = "yyyyMMddHHmmssSSS"; /** * 壓縮後檔案尾碼 */ private static final String AUDIT_FILE_ZIP_SUFFIX = ".zip"; /** * 壓縮前檔案尾碼 */ private static final String AUDIT_FILE_EXT = ".log"; private static final int ZIP_BUFFER = 4096; /** * 控制壓縮後的檔案解壓後是否帶base路徑 */ private static final String rootPath = ""; public static void main(String[] args) throws IOException { System.out.println(); new ZipFile().zipAuditLogFile("D:/tmp/successLog/logs/root.log"); } /** * 日誌壓縮 * * @param waitZipFile 要壓縮檔名 * @throws IOException */ private void zipAuditLogFile(String waitZipFile) throws IOException { File oldFile = new File(waitZipFile); if (!oldFile.exists()) { LOGGER.error("zipAuditLogFile name is {} not exist", waitZipFile); return; } //產生zip檔案名稱 DateFormat dataFormat = new SimpleDateFormat(AUDIT_LOG_FORMAT); String formatTime = dataFormat.format(oldFile.lastModified()); int end = waitZipFile.length() - AUDIT_FILE_EXT.length(); String zipFileName = waitZipFile.subSequence(0, end) + "_" + formatTime + AUDIT_FILE_ZIP_SUFFIX; File zipFile = new File(zipFileName); FileOutputStream zipfos = null; ZipOutputStream zipOs = null; CheckedOutputStream cos = null; try { zipfos = new FileOutputStream(zipFile); cos = new CheckedOutputStream(zipfos, new CRC32()); zipOs = new ZipOutputStream(cos); compress(oldFile, zipOs, rootPath); if (zipFile.exists()) { // 寫完的記錄檔許可權改為400 try { //linux上才可以運行,windows上需要裝cygwin並且把cygwin的bin目錄加到環境變數的path中才可以 Runtime.getRuntime().exec("chmod 400 -R " + zipFile); //壓縮後刪除舊檔案 boolean isDelete = oldFile.delete(); //建立新檔案 if (isDelete) { oldFile.createNewFile(); }// boolean isSuccess = PathUtil.setFilePermision(zipFile.toPath(), ARCHIVE_LOGFILE_PERMISION);// LOGGER.warn("set archive file: {}, permision result is {}", zipFile.getAbsolutePath(), isSuccess); } catch (IOException e) { LOGGER.error("set archive file:{} permision catch an error: {}", zipFile, e); } } } finally { if (null != zipOs) { zipOs.close(); } if (null != cos) { cos.close(); } if (null != zipfos) { zipfos.close(); } } } /** * 壓縮檔或目錄 * * @param oldFile 要壓縮的檔案 * @param zipOut 壓縮檔流 * @param baseDir baseDir * @throws IOException */ private void compress(File oldFile, ZipOutputStream zipOut, String baseDir) throws IOException { if (oldFile.isDirectory()) { compressDirectory(oldFile, zipOut, baseDir); } else { compressFile(oldFile, zipOut, baseDir); } } /** * 壓縮目錄 * * @param dir 要壓縮的目錄 * @param zipOut 壓縮檔流 * @param baseDir baseDir * @throws IOException */ private void compressDirectory(File dir, ZipOutputStream zipOut, String baseDir) throws IOException { File[] files = dir.listFiles(); for (File file : files) { compress(file, zipOut, baseDir + dir.getName() + File.separator); } } /** * 壓縮檔 * * @param oldFile 要壓縮的檔案 * @param zipOut 壓縮檔流 * @param baseDir baseDir * @throws IOException */ private void compressFile(File oldFile, ZipOutputStream zipOut, String baseDir) throws IOException { if (!oldFile.exists()) { LOGGER.error("zipAuditLogFile name is {} not exist", oldFile); return; } BufferedInputStream bis = null; try { bis = new BufferedInputStream(new FileInputStream(oldFile)); ZipEntry zipEntry = new ZipEntry(baseDir + oldFile.getName()); zipOut.putNextEntry(zipEntry); int count; byte data[] = new byte[ZIP_BUFFER]; while ((count = bis.read(data, 0, ZIP_BUFFER)) != -1) { zipOut.write(data, 0, count); } } finally { if (null != bis) { bis.close(); } } }}
java壓縮結果
修改許可權也可以利用Java7中NIO.2對中繼資料檔案操作的支援,具體可以查看NIO包的使用,其相關教程見文末說明。
代碼如下:
package com.website.common;import java.io.IOException;import java.nio.file.FileSystems;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.attribute.PosixFilePermission;import java.nio.file.attribute.PosixFilePermissions;import java.util.Set;/*** 提供檔案路徑公用函數 改變許可權,判斷是否正規檔案,判斷是否路徑在安全路徑下等** @program: website* @description: 路徑工具, 修改許可權* @author: smallsoup* @create: 2018-08-14 07:56**/public class PathUtil { /** * POSIX表示可移植作業系統介面,並不局限於unix類系統 */ private static final boolean ISPOSIX = FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); /** * 數字許可權格式,如600 */ private static final int PERM_LEN_THREE = 3; /** * 如765 rwxrw_r_x */ private static final int PERM_LEN_NINE = 9; /** * 設定檔案的許可權,盡在posix下有效 * * @param file 檔案 * @param perm 許可權 類似 “rw-r-----”, "640" * @return true 修改成功 false 修改失敗 * @throws IOException */ public static boolean setFilePermision(Path file, String perm) throws IOException { if (!ISPOSIX) { return true; } // 750 -> "rwxr-x---" if (perm.length() == PERM_LEN_THREE) { perm = trans2StrPerm(perm); } if (perm.length() != PERM_LEN_NINE) { return false; } Set<PosixFilePermission> perms = PosixFilePermissions.fromString(perm); Files.setPosixFilePermissions(file, perms); return true; } /** * 轉換 * * @param digitPerm 長度為3的數字字串 * @return */ private static String trans2StrPerm(String digitPerm) { StringBuilder builder = new StringBuilder(9); // owner builder.append(toStringPerm(digitPerm.charAt(0))); // group builder.append(toStringPerm(digitPerm.charAt(1))); // other builder.append(toStringPerm(digitPerm.charAt(2))); return builder.toString(); } private static String toStringPerm(char ch) { switch (ch - '0') { case 7: return "rwx"; case 6: return "rw-"; case 5: return "r-x"; case 4: return "r--"; case 3: return "-wx"; case 2: return "-w-"; case 1: return "--x"; case 0: return "---"; default: return ""; } }}
go語言、NIO等學習資料 可以關注文末公眾號後在後台回複【1】 擷取。
最後,csdn資源,收集了海量學習資料,如果你準備入IT坑,勵志成為優秀的程式猿,那麼這些資源很適合你,包括java、go、python、springcloud、elk、嵌入式 、大資料、面試資料、前端等資源。同時我們組建了一個技術交流群,裡面有很多大佬,會不定時分享技術文章,如果你想來一起學習提高,可以關注以下公眾號後回複【2】,擷取。
我是小碗湯,我們一起學習,掃碼關注,精彩內容第一時間推給你
歡迎掃碼關注