java、golang日志文件转储压缩实现

我的小碗汤 · · 1677 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

日志的转储和压缩是非常关键的,它不仅可以减少硬盘空间占用,主要还可以在发生故障时根据日志定位出故障原因。下面来看看golang和java的文件转储实现。

go语言:

用到了filepath包下的Walk方法,具体说明可以参看历史文章:
go语言path/filepath包之Walk源码解析

package main

import (
 "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】,获取。


我是小碗汤,我们一起学习,扫码关注,精彩内容第一时间推给你

欢迎扫码关注

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:我的小碗汤

查看原文:java、golang日志文件转储压缩实现

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1677 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传