使用StringBuilder与PrintWriter输出CSV多行数据异常问题
问题分析与修复方案
我帮你拆解下这两个核心问题的根源,然后给出针对性的修复代码:
问题1:CSV文件行数远超预期(内容异常)
你遇到的“600多行”其实是视觉错觉+数据累积bug导致的:
- Model类的
position是成员变量,每次调用getPos()都会往里面追加所有粒子的坐标,而不是生成当前时刻的新坐标串。比如第1次调用存100个粒子的坐标,第2次就变成200个,以此类推,每行的内容会越来越长,文本编辑器会自动折行,看起来像几百行。 - 同时每行的列数完全不符合预期,本该是
1+200列,结果变成1+200*N列,破坏了CSV格式。
问题2:启用position.setLength(0)后无数据
你之前把清空语句放在了getPos()的for循环内部,这会导致每次循环都清空position,最后只保留最后一个粒子的坐标。另外,Controller里的PrintWriter没有关闭/刷新,缓冲区的数据可能没写入文件,这也会导致文件为空。
修复后的代码
1. 修改Model类
- 将
position.setLength(0)移到for循环外,确保每次生成坐标前清空旧数据 - 去掉每行末尾多余的逗号,保证CSV格式合规
import java.util.ArrayList; public class Model { public int numberofparticles; public ArrayList<Particle> particlelist; public StringBuilder position = new StringBuilder(); Model() { particlelist = new ArrayList<Particle>(); numberofparticles = 100; for (int i = 0; i < numberofparticles; i++) { particlelist.add(new Particle()); } } public void updatePos() { for (int i = 0; i < numberofparticles; i++) { particlelist.get(i).x += 2*Math.cos(Math.random()*2*Math.PI); particlelist.get(i).y += 2*Math.sin(Math.random()*2*Math.PI); } } public StringBuilder getPos() { position.setLength(0); // 每次生成坐标前清空旧数据 for (int i=0; i < numberofparticles; i++) { position.append(particlelist.get(i).x); position.append(","); position.append(particlelist.get(i).y); // 最后一个粒子不加多余的逗号 if (i != numberofparticles - 1) { position.append(","); } } return position; } public class Particle { private double x; private double y; public Particle(double setX,double setY) { x = setX; y = setY; } Particle() { this(500+250*2*Math.cos(Math.random()*2*Math.PI), 300+150*2*Math.sin(Math.random()*2*Math.PI)); } public double getX() { return x; } public double getY() { return y; } } }
2. 修改Controller类
- 将
time改为double类型,保证时间值能正确递增(之前int类型会截断小数) - 调整循环条件,确保只生成100行数据
- 关闭
PrintWriter,强制缓冲区数据写入文件
import javax.swing.event.*; import java.awt.event.*; import java.io.FileNotFoundException; import java.io.PrintWriter; import javax.swing.*; public class Controller extends JPanel implements ActionListener{ Model model; View view; private Timer timer; private int delta = 100; private StringBuilder csv = new StringBuilder(); private int counter = 0; private double time = 2000.0; // 改为double类型,避免小数截断 public Controller(Model m, View v) { model = m; view = v; timer = new Timer(delta, this); timer.setInitialDelay((int)time); timer.start(); } public void actionPerformed(ActionEvent arg0) { // 写入当前时刻的行数据 csv.append(time); csv.append(","); csv.append(model.getPos()); csv.append("\n"); model.updatePos(); view.repaint(); time += delta * 0.001; counter++; // 生成100行后停止并写入文件 if (counter >= 100) { timer.stop(); PrintWriter pw = null; try { pw = new PrintWriter("data.csv"); pw.print(csv); // 用print避免多一行空行 } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (pw != null) { pw.close(); // 关闭流,确保数据写入文件 } } } } }
3. 可选优化:View类修复绘制异常
View类的paint方法需要调用super.paint(g),否则可能出现画布残留问题:
import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import javax.swing.*; public class View extends JPanel{ Model model; View(Model m){ model = m; this.setPreferredSize(new Dimension(1010,610)); } public void paint(Graphics g) { super.paint(g); // 添加此行,清空画布并执行默认绘制逻辑 g.setColor(Color.DARK_GRAY); for (int i=0; i < model.numberofparticles; i++) { g.fillOval((int)(model.particlelist.get(i).getX()), (int) (model.particlelist.get(i).getY()), 3, 3); } } }
修复后效果验证
- CSV文件会精确生成100行,每行格式严格符合
timeN, x1,y1,x2,y2,…x100,y100 - 时间值从2000.0开始,每次递增0.1,符合预期
- 启用
position.setLength(0)后不再出现无数据问题
内容的提问来源于stack exchange,提问作者armara
相关产品推荐
相关产品推荐

