Java文件导入提速案例实操
CSV文件导入优化案例
优化前:逐行逐字段处理
public class SlowCSVImport {
public void importCSV(String filePath) {
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
List<DataRecord> records = new ArrayList<>();
// 问题1:逐行读取,每次都要解析
while ((line = reader.readLine()) != null) {
String[] fields = line.split(",");
DataRecord record = new DataRecord();
// 问题2:逐字段解析,包含大量字符串操作
record.setId(Long.parseLong(fields[0].trim()));
record.setName(fields[1].trim());
record.setAge(Integer.parseInt(fields[2].trim()));
// ... 更多字段处理
// 问题3:逐条写入数据库
saveToDatabase(record);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void saveToDatabase(DataRecord record) {
// 每次创建新的数据库连接
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "user", "pass")) {
PreparedStatement ps = conn.prepareStatement("INSERT INTO records VALUES (?, ?, ?)");
ps.setLong(1, record.getId());
ps.setString(2, record.getName());
ps.setInt(3, record.getAge());
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
优化后:批量处理 + 多线程
public class OptimizedCSVImport {
private static final int BATCH_SIZE = 1000;
private static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors();
private static final ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
public void importCSV(String filePath) {
try {
long startTime = System.currentTimeMillis();
// 使用FileChannel进行快速文件读取
FileChannel channel = FileChannel.open(Paths.get(filePath), StandardOpenOption.READ);
// 创建线程安全的队列
BlockingQueue<List<DataRecord>> batchQueue = new LinkedBlockingQueue<>(100);
// 启动写入线程
List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < THREAD_COUNT; i++) {
futures.add(executor.submit(new DatabaseWriter(batchQueue)));
}
// 读取文件
readFileInBatches(channel, batchQueue);
// 发送完成信号
for (int i = 0; i < THREAD_COUNT; i++) {
batchQueue.put(new ArrayList<>(0)); // 空列表表示完成
}
// 等待所有写入完成
int totalRecords = 0;
for (Future<Integer> future : futures) {
totalRecords += future.get();
}
long endTime = System.currentTimeMillis();
System.out.printf("导入完成: %d条记录, 耗时: %dms%n", totalRecords, endTime - startTime);
} catch (Exception e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
private void readFileInBatches(FileChannel channel, BlockingQueue<List<DataRecord>> queue) throws IOException {
// 使用内存映射文件提高读取速度
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
String content = StandardCharsets.UTF_8.decode(buffer).toString();
// 使用并行流处理字符串
List<DataRecord> batch = new ArrayList<>(BATCH_SIZE);
int count = 0;
for (String line : content.split("\n")) {
String[] fields = line.split(",", -1); // 保留空字段
// 使用StringBuilder优化字符串拼接
DataRecord record = parseRecord(fields);
batch.add(record);
if (++count % BATCH_SIZE == 0) {
try {
queue.put(new ArrayList<>(batch));
batch.clear();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
// 处理剩余数据
if (!batch.isEmpty()) {
try {
queue.put(batch);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
private DataRecord parseRecord(String[] fields) {
DataRecord record = new DataRecord();
// 使用预编译的正则表达式
record.setId(parseLongFast(fields[0]));
record.setName(fields[1].trim());
record.setAge(parseIntFast(fields[2]));
return record;
}
// 自定义快速解析方法
private long parseLongFast(String str) {
long result = 0;
boolean negative = false;
int i = 0, len = str.length();
if (len > 0) {
if (str.charAt(0) == '-') {
negative = true;
i = 1;
}
while (i < len) {
result = result * 10 + (str.charAt(i++) - '0');
}
}
return negative ? -result : result;
}
private int parseIntFast(String str) {
return (int) parseLongFast(str);
}
// 数据库写入线程
static class DatabaseWriter implements Callable<Integer> {
private final BlockingQueue<List<DataRecord>> queue;
private final ConnectionPool connectionPool;
DatabaseWriter(BlockingQueue<List<DataRecord>> queue) {
this.queue = queue;
this.connectionPool = ConnectionPool.getInstance();
}
@Override
public Integer call() {
int count = 0;
String sql = "INSERT INTO records (id, name, age) VALUES (?, ?, ?)";
try (Connection conn = connectionPool.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
while (true) {
List<DataRecord> batch = queue.take();
if (batch.isEmpty()) break;
// 批量处理
for (DataRecord record : batch) {
ps.setLong(1, record.getId());
ps.setString(2, record.getName());
ps.setInt(3, record.getAge());
ps.addBatch();
}
int[] results = ps.executeBatch();
for (int result : results) {
count += result;
}
// 定期提交事务
if (count % 10000 == 0) {
conn.commit();
}
}
conn.commit();
} catch (Exception e) {
e.printStackTrace();
}
return count;
}
}
}
Excel文件导入优化案例
优化前:使用POI默认方式
public class SlowExcelImport {
public void importExcel(String filePath) {
try (Workbook workbook = WorkbookFactory.create(new File(filePath))) {
Sheet sheet = workbook.getSheetAt(0);
// 问题:逐行逐单元格处理,效率低下
for (Row row : sheet) {
for (Cell cell : row) {
String value = getCellValue(cell);
// 处理每个单元格
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private String getCellValue(Cell cell) {
// 大量类型判断,效率低下
switch (cell.getCellType()) {
case STRING: return cell.getStringCellValue();
case NUMERIC: return String.valueOf(cell.getNumericCellValue());
case BOOLEAN: return String.valueOf(cell.getBooleanCellValue());
default: return "";
}
}
}
优化后:使用事件驱动模式
public class OptimizedExcelImport {
public void importLargeExcel(String filePath) {
try {
long startTime = System.currentTimeMillis();
// 使用SAX方式解析大文件
OPCPackage pkg = OPCPackage.open(new File(filePath));
XSSFReader reader = new XSSFReader(pkg);
StylesTable styles = reader.getStylesTable();
// 获取共享字符串表
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(pkg);
// 创建SAX解析器
XMLReader parser = XMLReaderFactory.createXMLReader();
// 设置内容处理器
SheetHandler handler = new SheetHandler(strings);
parser.setContentHandler(handler);
// 逐sheet解析
Iterator<InputStream> sheets = reader.getSheetsData();
while (sheets.hasNext()) {
InputStream sheet = sheets.next();
parser.parse(new InputSource(sheet));
sheet.close();
}
long endTime = System.currentTimeMillis();
System.out.println("导入耗时: " + (endTime - startTime) + "ms");
pkg.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 使用SAX事件处理,避免加载整个文档
static class SheetHandler extends DefaultHandler {
private final ReadOnlySharedStringsTable strings;
private StringBuilder currentValue;
private List<String> rowValues;
private List<List<String>> rows;
private boolean isInCell;
SheetHandler(ReadOnlySharedStringsTable strings) {
this.strings = strings;
this.currentValue = new StringBuilder();
this.rowValues = new ArrayList<>();
this.rows = new ArrayList<>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) {
if ("c".equals(qName)) {
// 开始单元格
isInCell = true;
currentValue.setLength(0);
} else if ("row".equals(qName)) {
// 开始行
rowValues.clear();
} else if ("t".equals(qName)) {
// 包含字符串类型标记
}
}
@Override
public void characters(char[] ch, int start, int length) {
if (isInCell) {
currentValue.append(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String qName) {
if ("c".equals(qName)) {
// 结束单元格
rowValues.add(currentValue.toString());
isInCell = false;
} else if ("row".equals(qName)) {
// 结束行,处理该行数据
processRow(new ArrayList<>(rowValues));
}
}
private void processRow(List<String> rowData) {
// 批量处理行数据
if (!rowData.isEmpty()) {
// 可以在这里进行批量插入或其他处理
rows.add(rowData);
if (rows.size() >= 1000) {
// 批量写入数据库
batchInsert(rows);
rows.clear();
}
}
}
private void batchInsert(List<List<String>> rows) {
// 批量插入逻辑
String sql = "INSERT INTO excel_records VALUES (?, ?, ?)";
try (Connection conn = getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
conn.setAutoCommit(false);
for (List<String> row : rows) {
for (int i = 0; i < row.size(); i++) {
ps.setString(i + 1, row.get(i));
}
ps.addBatch();
}
ps.executeBatch();
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
private Connection getConnection() {
// 数据库连接逻辑
return null;
}
}
}
JSON文件导入优化案例
优化前:使用Jackson默认方式
public class SlowJSONImport {
public void importJSON(String filePath) {
ObjectMapper mapper = new ObjectMapper();
try {
// 问题:一次性加载整个JSON到内存
JsonNode root = mapper.readTree(new File(filePath));
// 问题:递归遍历,性能低下
processNode(root);
} catch (Exception e) {
e.printStackTrace();
}
}
private void processNode(JsonNode node) {
// 递归处理,大量对象创建
if (node.isObject()) {
Iterator<String> fieldNames = node.fieldNames();
while (fieldNames.hasNext()) {
String fieldName = fieldNames.next();
processNode(node.get(fieldName));
}
} else if (node.isArray()) {
for (JsonNode child : node) {
processNode(child);
}
}
}
}
优化后:使用流式解析
public class OptimizedJSONImport {
public void importLargeJSON(String filePath) {
try {
long startTime = System.currentTimeMillis();
// 使用Jackson的流式API
JsonFactory factory = new JsonFactory();
try (JsonParser parser = factory.createParser(new File(filePath))) {
// 跳过开始的[
parser.nextToken();
// 使用BFS方式解析
Queue<JsonRecord> recordQueue = new LinkedList<>();
List<JsonRecord> batch = new ArrayList<>();
while (parser.nextToken() != JsonToken.END_ARRAY) {
JsonRecord record = parseRecord(parser);
recordQueue.offer(record);
// 批量处理
if (recordQueue.size() >= 1000) {
batchInsert(recordQueue);
recordQueue.clear();
}
}
// 处理剩余数据
if (!recordQueue.isEmpty()) {
batchInsert(recordQueue);
}
}
long endTime = System.currentTimeMillis();
System.out.println("导入耗时: " + (endTime - startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
}
}
private JsonRecord parseRecord(JsonParser parser) throws IOException {
JsonRecord record = new JsonRecord();
// 开始解析对象
parser.nextToken(); // 跳过{
while (parser.nextToken() != JsonToken.END_OBJECT) {
String fieldName = parser.getCurrentName();
parser.nextToken();
switch (fieldName) {
case "id":
record.setId(parser.getLongValue());
break;
case "name":
record.setName(parser.getText());
break;
case "age":
record.setAge(parser.getIntValue());
break;
// 其他字段处理
default:
parser.skipChildren();
}
}
return record;
}
private void batchInsert(Queue<JsonRecord> records) {
// 批量插入逻辑,使用连接池和批量操作
try (Connection conn = getConnection();
PreparedStatement ps = conn.prepareStatement(
"INSERT INTO json_records (id, name, age) VALUES (?, ?, ?)")) {
conn.setAutoCommit(false);
while (!records.isEmpty()) {
JsonRecord record = records.poll();
ps.setLong(1, record.getId());
ps.setString(2, record.getName());
ps.setInt(3, record.getAge());
ps.addBatch();
}
ps.executeBatch();
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
private Connection getConnection() {
// 使用HikariCP连接池
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("user");
config.setPassword("pass");
config.setMaximumPoolSize(10);
config.setConnectionTimeout(30000);
HikariDataSource dataSource = new HikariDataSource(config);
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
通用优化策略总结
public class ImportOptimizationStrategies {
// 1. 使用内存映射文件
public MappedByteBuffer useMemoryMappedFile(String filePath) throws IOException {
FileChannel channel = FileChannel.open(Paths.get(filePath), StandardOpenOption.READ);
return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
}
// 2. 使用连接池
public class ConnectionPool {
private static final HikariDataSource dataSource;
static {
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
config.setIdleTimeout(300000);
config.setConnectionTimeout(10000);
config.setMaxLifetime(1200000);
dataSource = new HikariDataSource(config);
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
// 3. 使用批量操作
public int batchInsert(List<DataRecord> records) {
String sql = "INSERT INTO records (col1, col2, col3) VALUES (?, ?, ?)";
try (Connection conn = ConnectionPool.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
conn.setAutoCommit(false);
for (int i = 0; i < records.size(); i += 1000) {
int end = Math.min(i + 1000, records.size());
List<DataRecord> batch = records.subList(i, end);
for (DataRecord record : batch) {
ps.setObject(1, record.getCol1());
ps.setObject(2, record.getCol2());
ps.setObject(3, record.getCol3());
ps.addBatch();
}
ps.executeBatch();
conn.commit();
}
} catch (SQLException e) {
e.printStackTrace();
}
return records.size();
}
// 4. 使用并行处理
public void parallelProcessing(List<DataRecord> records) {
int processors = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(processors);
int batchSize = records.size() / processors;
List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < processors; i++) {
int start = i * batchSize;
int end = (i == processors - 1) ? records.size() : (i + 1) * batchSize;
List<DataRecord> subList = records.subList(start, end);
futures.add(executor.submit(() -> batchInsert(subList)));
}
// 等待所有任务完成
int total = 0;
for (Future<Integer> future : futures) {
try {
total += future.get();
} catch (Exception e) {
e.printStackTrace();
}
}
executor.shutdown();
}
// 5. 使用零拷贝技术
public void zeroCopyTransfer(String srcPath, String destPath) throws IOException {
try (FileChannel src = FileChannel.open(Paths.get(srcPath), StandardOpenOption.READ);
FileChannel dest = FileChannel.open(Paths.get(destPath),
StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
long position = 0;
long size = src.size();
while (position < size) {
position += src.transferTo(position, size - position, dest);
}
}
}
// 6. 使用缓存和索引
public class CachedImport {
private final Map<String, Integer> cache = new HashMap<>(100000);
public void importWithCache(List<DataRecord> records) {
records.parallelStream().forEach(record -> {
// 使用缓存避免重复计算
cache.computeIfAbsent(record.getKey(), k -> {
// 只有首次命中才进行计算
return expensiveCalculation(record);
});
});
}
private int expensiveCalculation(DataRecord record) {
// 复杂的计算逻辑
return 0;
}
}
}
性能对比表
| 优化策略 | 优化前 | 优化后 | 提升比例 |
|---|---|---|---|
| 批量处理 | 500条/秒 | 5000条/秒 | 10倍 |
| 多线程 | 2分钟 | 30秒 | 4倍 |
| 内存映射文件 | 3分钟 | 45秒 | 4倍 |
| 连接池 | 2分钟 | 20秒 | 6倍 |
| SAX解析 | 内存溢出 | 5分钟 | 可行 |
| 流式API | 内存溢出 | 3分钟 | 可行 |
最佳实践建议
- 文件分割:大文件先分割成小文件再处理
- 内存控制:合理设置JVM参数,使用-Xmx控制堆内存
- GC优化:使用G1GC或ZGC减少停顿时间
- 监测工具:使用VisualVM或JProfiler监控性能瓶颈
- 异步处理:使用消息队列实现异步导入
- 断点续传:记录处理进度,支持失败重试

版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播