前言
需求:批量导出服务器端的log日志文件,筛选条件为日期和日志级别。(服务器端log日期存放在指定的目录,日志文件命名规则:
log_${level}_${yyyy-MM-dd}_${numer}.log
,其中level
是日志级别,yyyy-MM-dd
的日志打印日期,number
是切分日志文件的计数单位),要求根据传入的日期和日志级别的参数值,对应筛选出相应的日志文件,打包为压缩文件导出。
本此实例中以打 .tar.gz
压缩包为例,分为不筛选打包和添加筛选条件打包两种情况。
依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.21</version>
</dependency>
不添加筛选条件
/**
* 把一个目录下的所有文件和文件夹打成.tar.gz包(从当前的目录开始)
* <p>Method :createTarFile
* <p>Description : 打包文件 .tar.gz
*
* @param sourceFolder 需要打成.tar.gz包的目录(包含目录和目录下的所有文件和文件夹)例:E:/aarm/test
* @param tarGzPath 打成的tar包生成的目标目录 例: D:/tmp 最终打包会在 D:/tmp目录下生成 test.tar.gz包
* @param ignoreDir 需要忽略的目录
* @param tarGzFileName 打tar.gz包的名,例如:ide-sdk.tar.gz
*/
public static void createTarFile(String sourceFolder, String tarGzPath, String ignoreDir, String tarGzFileName) {
TarArchiveOutputStream tarOs = null;
try {
File tarGzFile = new File(tarGzPath);
if (!tarGzFile.exists()) {
tarGzFile.mkdirs();
}
File sourceFile = new File(sourceFolder);
if (!sourceFile.exists()) {
throw new FileNotFoundException("压缩的目录不存在。。。");
}
// 创建一个 FileOutputStream 到输出文件(.tar.gz)
File tarFile = new File(tarGzFile + "/" + tarGzFileName);
FileOutputStream fos = new FileOutputStream(tarFile);
// // 创建一个 GZIPOutputStream,用来包装 FileOutputStream 对象
GZIPOutputStream gos = new GZIPOutputStream(new BufferedOutputStream(fos));
// 创建一个 TarArchiveOutputStream,用来包装 GZIPOutputStream 对象
tarOs = new TarArchiveOutputStream(gos);
// 若不设置此模式,当文件名超过 100 个字节时会抛出异常,异常大致如下:
// is too long ( > 100 bytes)
// 具体可参考官方文档:http://commons.apache.org/proper/commons-compress/tar.html#Long_File_Names
tarOs.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
addFilesToTarGZ(sourceFile, "", tarOs, ignoreDir);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
tarOs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 把文件复制到.tar.gz包中 不过滤 目录下所有文件全部打包下载
*
* @param file 需要复制的文件或目录
* @param parent 父目录
* @param tarArchive tar包流
* @param ignoreDir 忽略的目录
* @throws IOException 异常
*/
public static void addFilesToTarGZ(File file, String parent, TarArchiveOutputStream tarArchive, String ignoreDir)
throws IOException {
//不要再包一层最上面的目录
if (parent.startsWith(ignoreDir + File.separator)) {
parent = parent.replace(ignoreDir + File.separator, File.separator);
}
String entryName = parent + file.getName();
// System.out.println("file.getName()------:" + file.getName());
if (!parent.equals("")) {
// 添加 tar ArchiveEntry
tarArchive.putArchiveEntry(new TarArchiveEntry(file, entryName));
}
if (file.isFile()) {
// 根据文件默判断过滤,将符合条件的日志文件写入到压缩文件中
String fileName = file.getName();
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
// 写入文件
IOUtils.copy(bis, tarArchive);
tarArchive.closeArchiveEntry();
bis.close();
} else if (file.isDirectory()) {
// 因为是个文件夹,无需写入内容,关闭即可
if (!parent.equals("")) {
tarArchive.closeArchiveEntry();
}
File[] files = file.listFiles();
if (files != null) {
// 读取文件夹下所有文件
for (File f : files) {
// 递归
addFilesToTarGZ(new File(f.getAbsolutePath()), entryName + File.separator, tarArchive, ignoreDir);
}
}
}
}
添加筛选条件
/**
* 把一个目录下的所有文件和文件夹打成.tar.gz包(从当前的目录开始)
* <p>Method :createTarFile
* <p>Description : 打包文件 .tar.gz
*
* @param sourceFolder 需要打成.tar.gz包的目录(包含目录和目录下的所有文件和文件夹)例:E:/aarm/test
* @param tarGzPath 打成的tar包生成的目标目录 例: D:/tmp 最终打包会在 D:/tmp目录下生成 test.tar.gz包
* @param ignoreDir 需要忽略的目录
* @param tarGzFileName 打tar.gz包的名,例如:ide-sdk.tar.gz
*/
public static void createTarFile(String sourceFolder, String tarGzPath, String ignoreDir, String tarGzFileName, String logLevel, String date) {
TarArchiveOutputStream tarOs = null;
try {
File tarGzFile = new File(tarGzPath);
if (!tarGzFile.exists()) {
tarGzFile.mkdirs();
}
File sourceFile = new File(sourceFolder);
if (!sourceFile.exists()) {
throw new FileNotFoundException("压缩的目录不存在。。。");
}
// 创建一个 FileOutputStream 到输出文件(.tar.gz)
File tarFile = new File(tarGzFile + "/" + tarGzFileName);
FileOutputStream fos = new FileOutputStream(tarFile);
// // 创建一个 GZIPOutputStream,用来包装 FileOutputStream 对象
GZIPOutputStream gos = new GZIPOutputStream(new BufferedOutputStream(fos));
// 创建一个 TarArchiveOutputStream,用来包装 GZIPOutputStream 对象
tarOs = new TarArchiveOutputStream(gos);
// 若不设置此模式,当文件名超过 100 个字节时会抛出异常,异常大致如下:
// is too long ( > 100 bytes)
// 具体可参考官方文档:http://commons.apache.org/proper/commons-compress/tar.html#Long_File_Names
tarOs.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
addFilesToTarGZ2(sourceFile, "", tarOs, ignoreDir, logLevel, date);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
tarOs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 把文件复制到.tar.gz包中 打包前添加 日期 日志级别的 过滤条件,至打包符合条件的
*
* @param file 需要复制的文件或目录
* @param parent 父目录
* @param tarArchive tar包流
* @param ignoreDir 忽略的目录
* @throws IOException 异常
*/
public static void addFilesToTarGZ2(File file, String parent, TarArchiveOutputStream tarArchive, String ignoreDir, String logLevel, String date)
throws IOException {
//不要再包一层最上面的目录
if (parent.startsWith(ignoreDir + File.separator)) {
parent = parent.replace(ignoreDir + File.separator, File.separator);
}
String entryName = parent + file.getName();
System.out.println("file.getName()--date-parent---:" + parent);
System.out.println("file.getName()--date-file---:" + file.getName());
if (file.isFile()) {
// 根据文件默判断过滤,将符合条件的日志文件写入到压缩文件中
String fileName = file.getName();
// 先筛选符合日期的
if (Strings.isNotBlank(date) && fileName.contains(date)) {
System.out.println("file.getName()--date-file---:" + fileName);
// 再筛选符合日志级别的
boolean infoOrError = (LogLevel.INFO.getValue().equals(logLevel)
|| LogLevel.ERROR.getValue().equals(logLevel)) && fileName.contains(logLevel);
boolean infoAndError = LogLevel.ALL.getValue().equals(logLevel);
if (infoOrError || infoAndError) {
if (!parent.equals("")) {
// 添加 tar ArchiveEntry
tarArchive.putArchiveEntry(new TarArchiveEntry(file, entryName));
}
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
// 写入文件
IOUtils.copy(bis, tarArchive);
tarArchive.closeArchiveEntry();
bis.close();
}
}
} else if (file.isDirectory()) {
// 因为是个文件夹,无需写入内容,关闭即可
/*if (!parent.equals("")) {
tarArchive.closeArchiveEntry();
}*/
File[] files = file.listFiles();
if (files != null) {
// 读取文件夹下所有文件
for (File f : files) {
// 递归
addFilesToTarGZ2(new File(f.getAbsolutePath()), entryName + File.separator, tarArchive, ignoreDir, logLevel, date);
}
}
}
}
方法中用于判断的自定义枚举类
public enum LogLevel {
ALL("all"), INFO("info"), ERROR("error");
String value;
LogLevel(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
测试demo
public static void main(String[] args) {
String sourceFilePath = "D:\\logs";
String tarFilePath = "D:\\test";
String tarFileName = "demo.tar.gz";
String date = "2022-08-31";
String logLevel = "error";
createTarFile(sourceFilePath, tarFilePath, "", tarFileName, logLevel, date);
}