From 6aee53dda2128e79b2acbc5941611c9e51863b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=81=E5=86=9C=E9=98=BF=E6=A5=A0?= Date: Thu, 16 Oct 2025 01:36:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=9D=E5=AD=98=E6=96=87=E4=BB=B6=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=94=B9=E4=B8=BAcsv=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/example/ImageDotMarker.java | 53 +++++++++++++------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/example/ImageDotMarker.java b/src/main/java/org/example/ImageDotMarker.java index 193e995..e864ff4 100644 --- a/src/main/java/org/example/ImageDotMarker.java +++ b/src/main/java/org/example/ImageDotMarker.java @@ -453,38 +453,57 @@ public class ImageDotMarker extends JFrame { } JFileChooser fileChooser = new JFileChooser(); - fileChooser.setSelectedFile(new File("mark_points.txt")); - fileChooser.setFileFilter(new FileNameExtensionFilter("文本文件 (*.txt)", "txt")); + + // 设置默认文件名,使用当前图片文件名作为基础 + String defaultFilename = "mark_points.csv"; + if (currentImagePath != null) { + File imageFile = new File(currentImagePath); + String imageName = imageFile.getName(); + // 移除图片扩展名 + int lastDotIndex = imageName.lastIndexOf('.'); + if (lastDotIndex > 0) { + imageName = imageName.substring(0, lastDotIndex); + } + defaultFilename = imageName + "_mark_points.csv"; + } + + fileChooser.setSelectedFile(new File(defaultFilename)); + fileChooser.setFileFilter(new FileNameExtensionFilter("CSV文件 (*.csv)", "csv")); int result = fileChooser.showSaveDialog(this); if (result == JFileChooser.APPROVE_OPTION) { try { File file = fileChooser.getSelectedFile(); - if (!file.getName().toLowerCase().endsWith(".txt")) { - file = new File(file.getAbsolutePath() + ".txt"); + if (!file.getName().toLowerCase().endsWith(".csv")) { + file = new File(file.getAbsolutePath() + ".csv"); } StringBuilder sb = new StringBuilder(); - // 添加头部信息 - sb.append("# 图片标记点坐标导出\n"); - if (currentImagePath != null) { - sb.append(String.format("# 来源图片: %s\n", new File(currentImagePath).getName())); - } - sb.append(String.format("# 导出时间: %s\n", new java.util.Date())); - sb.append("# ======================================\n\n"); - - // 添加标记点数据 + // CSV列标题 sb.append("序号,名称,X坐标,Y坐标\n"); + + // 添加标记点数据,确保CSV格式正确处理包含逗号或引号的名称 for (int i = 0; i < points.size(); i++) { MarkPoint p = points.get(i); - sb.append(String.format("%d,%s,%d,%d\n", i + 1, p.name, p.x, p.y)); + String quotedName = p.name; + // CSV格式要求:如果字段包含逗号、双引号或换行符,需要用双引号包围,且内部的双引号用两个双引号表示 + if (quotedName.contains(",") || quotedName.contains("\"") || quotedName.contains("\n")) { + quotedName = "\"" + quotedName.replace("\"", "\"\"") + "\""; + } + sb.append(String.format("%d,%s,%d,%d\n", i + 1, quotedName, p.x, p.y)); } - // 写入文件 - java.nio.file.Files.write(file.toPath(), sb.toString().getBytes("UTF-8")); + // 写入文件,使用UTF-8编码并添加BOM以支持Excel正确识别中文 + try (java.io.FileOutputStream fos = new java.io.FileOutputStream(file)) { + // 写入UTF-8 BOM + byte[] bom = {(byte)0xEF, (byte)0xBB, (byte)0xBF}; // UTF-8 BOM + fos.write(bom); + // 写入CSV内容 + fos.write(sb.toString().getBytes("UTF-8")); + } JOptionPane.showMessageDialog(this, "标记点坐标导出成功!\n保存位置: " + file.getAbsolutePath()); - updateStatusBar("已导出标记点坐标到文件"); + updateStatusBar("已导出标记点坐标到CSV文件"); } catch (IOException ex) { JOptionPane.showMessageDialog(this, "导出失败: " + ex.getMessage()); }