You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:42:10