日志的转储和压缩是非常关键的,它不仅可以减少硬盘空间占用,主要还可以在发生故障时根据日志定位出故障原因。下面来看看golang和java的文件转储实现。
用到了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压缩结果
说明见注释。
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 ""; } } }
最后,csdn资源,收集了海量学习资料,如果你准备入IT坑,励志成为优秀的程序猿,那么这些资源很适合你,包括java、go、python、springcloud、elk、嵌入式 、大数据、面试资料、前端等资源。同时我们组建了一个技术交流群,里面有很多大佬,会不定时分享技术文章,如果你想来一起学习提高,可以关注以下公众号后回复【2】,获取。
欢迎扫码关注