Background
这里只是对自己常用的工具类型做个整理记录。主要包括日期、数字、文件类型(csv文件的创建以及zip压缩)等的操作,项目结构如下图所示:
1、maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cloudansys</groupId>
<artifactId>cloudansys-utils</artifactId>
<version>1.0-SNAPSHOT</version>
<name>cloudansys-utils</name>
<description>工具类</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<lang3.version>3.3.2</lang3.version>
<fastjson.version>1.2.25</fastjson.version>
<jackson.version>2.9.8</jackson.version>
<joda.version>2.9.9</joda.version>
<commons-codec.version>1.10</commons-codec.version>
<commons-csv.version>1.8</commons-csv.version>
<commons-compress.version>1.18</commons-compress.version>
<lombok.version>1.18.6</lombok.version>
</properties>
<dependencies>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${lang3.version}</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${joda.version}</version>
</dependency>
<!--commons-csv-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>${commons-csv.version}</version>
</dependency>
<!-- commons-compress -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-archetype-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.cloudansys.util.main.CloudansysUtils</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>reference.conf</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2、CloudansysUtils
package com.cloudansys.util.main;
import com.alibaba.fastjson.JSONObject;
import com.cloudansys.util.entity.FileInfo;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author wlf
* @version V1.0
* @date 2021-03-03
*/
public class CloudansysUtils {
public CloudansysUtils() {
}
/**
* 【常用的字符或字符串】
* ps:静态内部类,不需要引用外部类的非静态属性/方法
*/
public static class Const {
// punctuation[ptn][标点]
public static final String PTN_LF = "\n";
public static final String PTN_EMPTY = "";
public static final String PTN_SPACE = " ";
public static final String PTN_COMMA = ",";
public static final String PTN_COLON = ":";
public static final String PTN_SLASH = "/";
public static final String PTN_PERIOD = "\\.";
public static final String PTN_ASTERISK = "*";
public static final String PTN_BAR_MID = "-";
public static final String PTN_BAR_BOTTOM = "_";
// format[fmt][格式]
private static final String FMT_DOUBLE = "%.nf";
public static final String FMT_TRIM_SEC = "yyyyMMddHHmmss";
public static final String FMT_TRIM_MILLI = "yyyyMMddHHmmssSSS";
public static final String FMT_STD_SEC = "yyyy-MM-dd HH:mm:ss";
public static final String FMT_STD_MILLI = "yyyy-MM-dd HH:mm:ss.SSS";
// string[str][字符或字符串]
public static final String STR_N = "n";
public static final String STR_ZERO = "0";
public static final String UNIT_B = "B";
public static final String UNIT_KB = "KB";
public static final String UNIT_MB = "MB";
public static final String UNIT_GB = "GB";
public static final String SUFFIX_CSV = ".csv";
public static final String SUFFIX_ZIP = ".zip";
}
/**
* 【处理数字类型】
*/
public static class NumUtil {
/**
* @param numDecimals 小数位数,例:5
* @return 返回精确到 numDecimals 位的格式,例:%.5f
*/
private static String getDoubleFmt(int numDecimals) {
return Const.FMT_DOUBLE.replaceAll(Const.STR_N, String.valueOf(numDecimals));
}
/**
* 获取指定范围的一组有序数集合,包含起始数据
*
* @param startValue 起始数值,例:1
* @param endValue 终止数值,例:5
* @return 返回一组有序数据的集合,例:[1,2,3,4,5]
*/
public static List<Integer> getSpecifyRange(int startValue, int endValue) {
List<Integer> resList = new ArrayList<>();
for (int i = startValue; i <= endValue; i++) {
resList.add(i);
}
return resList;
}
/**
* 格式化 double 类型的数值为 numDecimals 数据
*
* @param doubleValue 被格式化的数据,例:1.123456789
* @param numDecimals 小数位数,例:5
* @return 格式化后的数据,例:1.12345
*/
public static double formatDouble(double doubleValue, int numDecimals) {
return Double.parseDouble(String.format(getDoubleFmt(numDecimals), doubleValue));
}
/**
* 获取两个 double 类型数据的绝对值之和
*
* @param x 例:1.123
* @param y 例:-1.123
* @return 绝对值之和,例:2.246
*/
public static double getSumOfAbsDouble(double x, double y) {
return Math.abs(x) + Math.abs(y);
}
}
/**
* 【处理字符串类型】
*/
public static class StrUtil {
/**
* 判断字符串是不是 json 格式
*
* @param content 例:{"msg":"ok","status":200,"data":null}
* @return 例:true
*/
public static boolean isJson(String content) {
if (StringUtils.isEmpty(content)) {
return false;
}
boolean isJsonObject = true;
boolean isJsonArray = true;
try {
JSONObject.parseObject(content);
} catch (Exception e) {
isJsonObject = false;
}
try {
JSONObject.parseArray(content);
} catch (Exception e) {
isJsonArray = false;
}
return isJsonObject || isJsonArray;
}
/**
* 返回所给分隔符分隔的字符串
*
* @param delimiter 例:_
* @param strings 例:a,b,c
* @return 返回底杠分隔的字符串 例:a_b_c
*/
public static String delimitStrings(String delimiter, String... strings) {
StringBuilder buffer = new StringBuilder();
for (String string : strings) {
buffer.append(string).append(delimiter);
}
buffer.deleteCharAt(buffer.lastIndexOf(delimiter));
return buffer.toString();
}
/**
* 返回所给分隔符分隔的字符串
*
* @param delimiter 字符串数组,例:_
* @param dataArray 字符串数组,例:["a", "b", "c"]
* @return 返回底杠分隔的字符串,例:a_b_c
*/
public static String delimitArray(String delimiter, String[] dataArray) {
StringBuilder buffer = new StringBuilder();
for (String data : dataArray) {
buffer.append(data).append(delimiter);
}
buffer.deleteCharAt(buffer.lastIndexOf(delimiter));
return buffer.toString();
}
}
/**
* 【处理日期类型】
*/
public static class DateUtil {
/**
* 把输入的字符串日期格式化成日期类型
*
* @param srcDate 输入的字符串日期,例:20210107141320111
* @param srcFmt 输入的格式,需要与第一个参数的格式对应,例:yyyyMMddHHmmssSSS
* @return 返回日期
*/
public static Date toDate(String srcDate, String srcFmt) {
return DateTimeFormat.forPattern(srcFmt).parseDateTime(srcDate).toDate();
}
/**
* 返回 num 分钟前的秒级标准格式时间
*
* @param num 例:2
* @return 例:返回 num 分钟前的秒级标准格式时间
*/
public static String numMinAgoStdSec(int num) {
return new DateTime()
.minusMinutes(num)
.toString(Const.FMT_STD_SEC);
}
/**
* 判断第二个时间比第一个时间是否晚 n 秒以上
*
* @param firstStdSecDate 例:2020-11-17 13:10:00
* @param secondStdSecDate 例:2020-11-17 13:10:02
* @param secDiff 例:1
* @return 例:true
*/
public static boolean secDiffOfStdSec(String firstStdSecDate, String secondStdSecDate, Integer secDiff) {
return DateTimeFormat
.forPattern(Const.FMT_STD_SEC)
.parseDateTime(secondStdSecDate)
.minusSeconds(secDiff)
.isAfter(stdSecToMilliTs(firstStdSecDate));
}
/**
* 【毫秒级Influx格式时间】 ===> 【毫秒级标准格式时间】
*
* @param influxMilliDate 例:2021-01-07T14:13:20.111+08:00
* @return 例:2021-01-07 14:13:20.111
*/
public static String influxMilliToStdMilli(String influxMilliDate) {
return DateTime
.parse(influxMilliDate)
.toString(Const.FMT_STD_MILLI);
}
/**
* 【秒级Influx格式时间】 ===> 【秒级标准格式时间】
*
* @param influxSecDate 例:2021-01-07T14:13:20+08:00
* @return 例:2021-01-07 14:13:20
*/
public static String influxSecToStdSec(String influxSecDate) {
return DateTime
.parse(influxSecDate)
.toString(Const.FMT_STD_SEC);
}
/**
* 【毫秒级精简格式时间】 ===> 【毫秒级标准格式时间】
*
* @param trimMilliDate 例:20210107141320111
* @return 例:2021-01-07 14:13:20.111
*/
public static String trimMilliToStdMilli(String trimMilliDate) {
return DateTimeFormat
.forPattern(Const.FMT_TRIM_MILLI)
.parseDateTime(trimMilliDate)
.toString(Const.FMT_STD_MILLI);
}
/**
* 【毫秒级精简格式时间】 ===> 【秒级标准格式时间】
*
* @param trimMilliDate 例:20210107141320111
* @return 例:2021-01-07 14:13:20
*/
public static String trimMilliToStdSec(String trimMilliDate) {
return DateTimeFormat
.forPattern(Const.FMT_TRIM_MILLI)
.parseDateTime(trimMilliDate)
.toString(Const.FMT_STD_SEC);
}
/**
* 【毫秒级精简格式时间】 ===> 【时间戳】
*
* @param trimMilliDate 例:20210107141320111
* @return 例:1610000000111
*/
public static long trimMilliToMilliTs(String trimMilliDate) {
return DateTimeFormat
.forPattern(Const.FMT_TRIM_MILLI)
.parseDateTime(trimMilliDate)
.toDate()
.getTime();
}
/**
* 【秒级标准格式时间】 ===> 【13位时间戳】
*
* @param stdSecDate 例:2021-01-07 14:13:20
* @return 例:1610000000000
*/
public static long stdSecToMilliTs(String stdSecDate) {
return DateTimeFormat
.forPattern(Const.FMT_STD_SEC)
.parseDateTime(stdSecDate)
.toDate()
.getTime();
}
/**
* 【秒级标准格式时间】 ===> 【13位时间戳】
*
* @param stdMilliDate 例:2021-01-07 14:13:20.111
* @return 例:1610000000111
*/
public static long stdMilliToMilliTs(String stdMilliDate) {
return DateTimeFormat
.forPattern(Const.FMT_STD_MILLI)
.parseDateTime(stdMilliDate)
.toDate()
.getTime();
}
/**
* 【13位时间戳】 ===> 【秒级标准格式时间】
*
* @param milliTs 例:1610000000111
* @return 例:2021-01-07 14:13:20
*/
public static String milliTsToStdSec(Object milliTs) {
return new DateTime(Long.parseLong(milliTs.toString()))
.toString(Const.FMT_STD_SEC);
}
/**
* 【13位时间戳】 ===> 【毫秒级标准格式时间】
*
* @param milliTs 例:1610000000111
* @return 例:2021-01-07 14:13:20.111
*/
public static String milliTsToStdMilli(Object milliTs) {
return new DateTime(Long.parseLong(milliTs.toString()))
.toString(Const.FMT_STD_MILLI);
}
}
/**
* 【处理文件类型】
*/
public static class FileUtil {
/**
* 返回文件大小,带单位(例:4KB、4MB、4GB等)
* 大于1024b返回kb,大于1024kb返回mb,大于1024mb返回gb
*
* @param filename 文件名 例:data/export/data-20210322171359.zip
*/
public static String getFileSize(String filename) {
File file = new File(filename);
if (!file.exists() || !file.isFile()) {
return null;
}
double length = (double) file.length();
String fileSize = null;
if (length < 1024) {
fileSize = length + Const.UNIT_B;
} else if (length > 1024 && length < Math.pow(length, 2)) {
fileSize = NumUtil.formatDouble(
length / 1024, 1) + Const.UNIT_KB;
} else if (length > Math.pow(length, 2) && length < Math.pow(length, 3)) {
fileSize = NumUtil.formatDouble(
length / Math.pow(length, 2), 1) + Const.UNIT_MB;
} else if (length > Math.pow(length, 3) && length < Math.pow(length, 4)) {
fileSize = NumUtil.formatDouble(
length / Math.pow(length, 3), 1) + Const.UNIT_GB;
}
return fileSize;
}
/**
* 创建 csv 文件
*
* @param fileInfo 文件实体类
* @return 返回生成的 csv 文件的路径
*/
public static String createCsvFile(FileInfo fileInfo) {
File csvFile = null;
try {
csvFile = new File(
fileInfo.getPath() + File.separator + fileInfo.getName() + Const.SUFFIX_CSV);
File parent = csvFile.getParentFile();
if (parent != null && !parent.exists()) {
parent.mkdirs();
}
csvFile.createNewFile();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(csvFile), StandardCharsets.UTF_8));
CSVPrinter printer = CSVFormat.EXCEL.print(writer);
// 写入文件头部
printer.printRecord(fileInfo.getHead());
// 写入文件内容
for (List<Object> row : fileInfo.getData()) {
printer.printRecord(row);
}
printer.flush();
printer.close();
return csvFile.getPath();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 把文件或目录进行 zip 压缩,压缩后的文件名与原文件名相同,后缀为 zip
* 例如:data-20210322171359 -> data-20210322171359.zip
*
* @param fileName 文件或目录
*/
public static void zipCompress(String fileName) {
String zipFile = fileName + Const.SUFFIX_ZIP;
ZipOutputStream out = null;
try {
out = new ZipOutputStream(new FileOutputStream(zipFile));
doCompress(new File(fileName), out, Const.PTN_EMPTY);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 私有方法
*/
private static void doCompress(File inFile, ZipOutputStream out, String dir) throws IOException {
if (inFile.isDirectory()) {
File[] files = inFile.listFiles();
if (files != null && files.length > 0) {
for (File file : files) {
String name = inFile.getName();
if (!Const.PTN_EMPTY.equals(dir)) {
name = dir + Const.PTN_SLASH + name;
}
doCompress(file, out, name);
}
}
} else {
compress(inFile, out, dir);
}
}
/**
* 私有方法
*/
private static void compress(File inFile, ZipOutputStream out, String dir) throws IOException {
String entryName;
if (!Const.PTN_EMPTY.equals(dir)) {
entryName = dir + Const.PTN_SLASH + inFile.getName();
} else {
entryName = inFile.getName();
}
ZipEntry entry = new ZipEntry(entryName);
out.putNextEntry(entry);
int len;
byte[] buffer = new byte[1024];
FileInputStream fis = new FileInputStream(inFile);
while ((len = fis.read(buffer)) > 0) {
out.write(buffer, 0, len);
out.flush();
}
out.closeEntry();
fis.close();
}
}
}
3、FileInfo
package com.cloudansys.util.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* 文件实体类
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FileInfo implements Serializable {
private static final long serialVersionUID = 1L;
// 文件路径
private String path;
// 文件名称
private String name;
// 文件头部
private List<Object> head;
// 文件数据
private List<List<Object>> data;
}
4、数据导出文件格式(qj1.csv)
数据时间,X轴(m/s²),Y轴(m/s²)
2021-03-18 15:36:59 GMT+08:00,7.30046,5.95816
2021-03-18 15:36:58 GMT+08:00,6.14289,6.24979
2021-03-18 15:36:57 GMT+08:00,3.30854,4.77823
2021-03-18 15:36:56 GMT+08:00,7.62144,8.03541
2021-03-18 15:36:55 GMT+08:00,4.58577,7.33067
2021-03-18 15:36:54 GMT+08:00,3.60853,4.27457
2021-03-18 15:36:53 GMT+08:00,9.87298,2.37898
2021-03-18 15:36:52 GMT+08:00,3.26174,5.397
2021-03-18 15:36:51 GMT+08:00,2.72505,5.80124
2021-03-18 15:36:50 GMT+08:00,3.35503,7.31491
2021-03-18 15:36:49 GMT+08:00,3.91291,4.13488
2021-03-18 15:36:48 GMT+08:00,7.86633,1.35536
2021-03-18 15:36:47 GMT+08:00,4.16187,3.62362
2021-03-18 15:36:46 GMT+08:00,7.92665,2.03053