背景
公司业务,要将数据要做本地备份记录,开始直接保存json格式,但是太占用存储,所以使用csv格式保存。
思路
1、使用csvWriter ,数据来时,将数据写入本地
不足:
如果每次数据来临时,创建一个csvWriter性能有影响,批量写入也可以,这不是主要原因。主要原因是,需要考虑什么时候创建csv文件,什么时候关闭csv流,当项目升级时,也要关闭流。注意的点太多(放弃)
2、csv其实就是一个文本,每行数据就是用逗号分割,我们可以将数据逗号分割好,直接使用info(data)来记录数据。
难点是,如何将标头写入文件。
自定义Appender、Encoder
xml文件
xml
<appender name="USER_LOG" class="com.sjy.logback.CsvRollingFileAppender">
<encoder class="com.sjy.logback.CsvPatternLayoutEncoder">
<fileHeader>time,data,user,url</fileHeader>
<charset>UTF-8</charset>
<pattern>%msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>/var/log/user-data.%d{yyyy-MM-dd}.csv</FileNamePattern>
<MaxHistory>7</MaxHistory>
</rollingPolicy>
</appender>
<logger name="userLogger" level="INFO" additivity="false">
<appender-ref ref="USER_LOG" />
</logger>
CsvRollingFileAppender.java
java
import ch.qos.logback.core.FileAppender;
import ch.qos.logback.core.encoder.Encoder;
import ch.qos.logback.core.recovery.ResilientFileOutputStream;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.util.FileUtil;
import java.io.File;
import java.io.IOException;
/*
判断文件是否存在,如果存在,将header 去除,如果不存在添加fileHeader
*/
public class CsvRollingFileAppender<E> extends RollingFileAppender<E> {
@Override
public void openFile(String file_name) throws IOException {
lock.lock();
try {
File file = new File(file_name);
boolean result = FileUtil.createMissingParentDirectories(file);
if (!result) {
addError("Failed to create parent directories for [" + file.getAbsolutePath() + "]");
}
ResilientFileOutputStream resilientFos = new ResilientFileOutputStream(file, append, FileAppender.DEFAULT_BUFFER_SIZE);
resilientFos.setContext(context);
CsvPatternLayoutEncoder encoder = (CsvPatternLayoutEncoder) this.getEncoder();
String fileHeader = null;
// 文件是否存在
boolean isNew = !file.exists() || file.length() <= 0;
if (!isNew) {
// 设置null
fileHeader = encoder.getFileHeader();
encoder.setPatternLayoutFileHeader(null);
}
// 写入文件
setOutputStream(resilientFos);
if (!isNew) {
encoder.setPatternLayoutFileHeader(fileHeader);
}
} finally {
lock.unlock();
}
}
}
CsvPatternLayoutEncoder .java
java
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.pattern.PatternLayoutEncoderBase;
public class CsvPatternLayoutEncoder extends PatternLayoutEncoderBase<ILoggingEvent> {
private String fileHeader;
private PatternLayout patternLayout;
@Override
public void start() {
patternLayout = new PatternLayout();
patternLayout.setContext(context);
patternLayout.setPattern(getPattern());
patternLayout.setFileHeader(getFileHeader());
patternLayout.setOutputPatternAsHeader(outputPatternAsHeader);
patternLayout.start();
this.layout = patternLayout;
super.start();
}
public String getFileHeader() {
return fileHeader;
}
public void setFileHeader(String fileHeader) {
this.fileHeader = fileHeader;
}
public void setPatternLayoutFileHeader(String fileHeader) {
patternLayout.setFileHeader(fileHeader);
}
}
java
private static Logger log = LoggerFactory.getLogger("userLogger");
// 写入文件
public void logToFile() {
log.info(time+","+data+","+user+","+url);
}
注意事项
- 因为CSV是一个用逗号分割的文本,所以在
data
、user
数据中不要有逗号