|
|
|
@ -1,97 +0,0 @@
|
|
|
|
|
package com.dsideal.YunXiaoTools.Utils;
|
|
|
|
|
|
|
|
|
|
import com.jfinal.plugin.activerecord.Db;
|
|
|
|
|
import com.jfinal.plugin.activerecord.Record;
|
|
|
|
|
import com.opencsv.CSVWriter;
|
|
|
|
|
|
|
|
|
|
import java.io.BufferedWriter;
|
|
|
|
|
import java.io.FileWriter;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
public class CsvExportUtil {
|
|
|
|
|
private static final int BATCH_SIZE = 1000;
|
|
|
|
|
private static final String NULL_REPLACEMENT = "NULL"; // 使用NULL文本
|
|
|
|
|
/**
|
|
|
|
|
* 进度回调接口
|
|
|
|
|
*/
|
|
|
|
|
public interface ProcessCallback {
|
|
|
|
|
void onProgress(long processed, long total);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void exportToCsv(String sql, String filePath, ProcessCallback callback) {
|
|
|
|
|
// 获取总记录数
|
|
|
|
|
long totalCount = Db.queryLong("select count(*) from (select * " + sql + ") t");
|
|
|
|
|
long processedCount = 0;
|
|
|
|
|
|
|
|
|
|
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath), 8192);
|
|
|
|
|
CSVWriter writer = new CSVWriter(bufferedWriter,
|
|
|
|
|
'\t', // 使用Tab分隔符
|
|
|
|
|
CSVWriter.NO_QUOTE_CHARACTER, // 不使用引号
|
|
|
|
|
CSVWriter.DEFAULT_ESCAPE_CHARACTER,
|
|
|
|
|
CSVWriter.DEFAULT_LINE_END)) {
|
|
|
|
|
|
|
|
|
|
boolean isFirst = true;
|
|
|
|
|
int page = 1;
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
// 分页查询数据
|
|
|
|
|
List<Record> records = Db.paginate(page, BATCH_SIZE, "select *", sql).getList();
|
|
|
|
|
if (records.isEmpty()) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 第一次写入表头
|
|
|
|
|
if (isFirst) {
|
|
|
|
|
String[] headers = records.getFirst().getColumnNames();
|
|
|
|
|
writer.writeNext(headers, false); // false表示不加引号
|
|
|
|
|
isFirst = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 写入数据
|
|
|
|
|
for (Record record : records) {
|
|
|
|
|
String[] row = new String[record.getColumnNames().length];
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (String column : record.getColumnNames()) {
|
|
|
|
|
Object value = record.get(column);
|
|
|
|
|
row[i++] = formatValue(value);
|
|
|
|
|
}
|
|
|
|
|
writer.writeNext(row, false); // false表示不加引号
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新进度
|
|
|
|
|
processedCount += records.size();
|
|
|
|
|
if (callback != null) {
|
|
|
|
|
callback.onProgress(processedCount, totalCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 定期刷新缓冲区
|
|
|
|
|
bufferedWriter.flush();
|
|
|
|
|
|
|
|
|
|
page++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
throw new RuntimeException("导出CSV文件失败", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 格式化值
|
|
|
|
|
*/
|
|
|
|
|
private String formatValue(Object value) {
|
|
|
|
|
if (value == null) {
|
|
|
|
|
return NULL_REPLACEMENT;
|
|
|
|
|
}
|
|
|
|
|
String strValue = value.toString();
|
|
|
|
|
// 如果数据中包含Tab,替换为空格
|
|
|
|
|
return strValue.replace("\t", " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 不需要进度回调的重载方法
|
|
|
|
|
*/
|
|
|
|
|
public void exportToCsv(String sql, String filePath) {
|
|
|
|
|
exportToCsv(sql, filePath, null);
|
|
|
|
|
}
|
|
|
|
|
}
|