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

C#数据记录器无法创建CSV文件 求代码错误排查

问题描述

我正在开发一个基于C#(Visual Studio)的大学GUI项目,非编程专业。尝试实现一款数据记录器,需记录用户的所有操作及时间戳并保存为.csv文件,但程序始终无法创建该文件。预期关闭应用后文件会出现在桌面,记录所有操作记录,恳请帮忙检查代码是否合理,指出错误位置。

存在问题的代码
using ClosedXML.Excel;
using DocumentFormat.OpenXml.Drawing.Diagrams;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.IO.Ports;

namespace Proyecto_controlLed_Servo
{
    public partial class Form1 : Form
    {
        private List<string> receivedDataList = new List<string>();
        private bool _isRunning = true;

        public Form1()
        {
            CheckForIllegalCrossThreadCalls = false;
            receivedDataList = new List<string>();

            SP1.DataReceived += new SerialDataReceivedEventHandler(SP1_DataReceived);
            SP1.ErrorReceived += new SerialErrorReceivedEventHandler(SP1_ErrorReceived);
            SP1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
            LogAlert("Aplicación iniciada");
        }

        private void bCon_Click(object sender, EventArgs e)
        {
            try
            {
                if (!SP1.IsOpen)
                {
                    SP1.PortName = CBPort.Text;
                    SP1.Open();
                    LogAlert("Conexión Establecida");
                    receivedDataList.Add("Conexión al puerto COM establecida.");

                    PBConexion.Value = 100;
                    enableComponents();
                }
            }
            catch (Exception error)
            {
                MessageBox.Show("Error al conectarse al puerto: " + error.Message);
            }
        }

        private void bDis_Click(object sender, EventArgs e)
        {
            if (SP1.IsOpen)
            {
                try
                {
                    //Enviar comando para apagar steppers y cerrar puerto COM
                    SP1.WriteLine("l");
                    SP1.Close();
                    LogAlert("Gimb-App desconectado");
                    receivedDataList.Add("Se ha desconectado del puerto COM.");

                    MessageBox.Show("Entrada COM desconectada");
                    PBConexion.Value = 0;
                    labelEstado.Text = "Estado actual: Desconectado";
                }
                catch (Exception error)
                {
                    MessageBox.Show("Error al desconectar el puerto: " + error.Message);
                }
            }
        }

        private void BRef_Click(object sender, EventArgs e)
        {
            try
            {
                string[] ports = SerialPort.GetPortNames();
                CBPort.Items.Clear();
                CBPort.Items.AddRange(ports);
                if (ports.Length > 0)
                {
                    CBPort.SelectedIndex = 0;
                }
                MessageBox.Show("Lista de puertos actualizada");
                receivedDataList.Add("Se refrescó la lista de puertos COM.");
            }
            catch (Exception error)
            {
                MessageBox.Show("Error al refrescar la lista de puertos: " + error.Message);
            }
        }

        //Método para registrar alertas
        private void LogAlert(string message)
        {
            string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            receivedDataList.Add($"{timestamp}:{message}");
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (SP1.IsOpen)
            {
                try
                {
                    SP1.WriteLine("l");
                    SP1.Close();
                }
                catch (Exception error)
                {
                    MessageBox.Show("Error al cerrar la aplicación: " + error.Message);
                }
            }
            _isRunning = false;
            SaveDataToCsv();
        }

        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            if (!_isRunning) return;

            try
            {
                string data = SP1.ReadLine();
                receivedDataList.Add("Dato recibido: " + data);
                Console.WriteLine("Dato recibido: " + data);
            }
            catch (Exception error)
            {
                receivedDataList.Add("Error al recibir datos: " + error.Message);
            }
        }

        private void SaveDataToCsv()
        {
            try
            {
                string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                string filePath = Path.Combine(desktopPath, "RegistroGimb.csv");
                string csvFilePath = Path.ChangeExtension(filePath, ".csv");

                using (var workbook = new XLWorkbook())
                {
                    var worksheet = workbook.Worksheets.Add("Registros");
                    worksheet.Cell(1, 1).Value = "Registro de Actividades";
                    for (int i = 0; i < receivedDataList.Count; i++)
                    {
                        worksheet.Cell(i + 2, 1).Value = receivedDataList[i];
                    }

                    workbook.SaveAs("RegistroGimb.xlsx"); //guardar como archivo .xlsx
                }

                ConvertXlsxToCsv(filePath, csvFilePath);

                MessageBox.Show("Registro de alertas guardado en {filePath}");
            }
            catch (Exception error)
            {
                MessageBox.Show("Error al escribir en el archivo de registro: " + error.Message);
            }
        }

        private void ConvertXlsxToCsv(string filePath, string csvFilePath)
        {
            try
            {
                using (var workbook = new XLWorkbook(filePath))
                {
                    var worksheet = workbook.Worksheet(1);

                    using (var writer = new StreamWriter(csvFilePath))
                    {
                        foreach (var row in worksheet.RowsUsed())
                        {
                            var cells = row.CellsUsed().Select(c => c.GetValue<string>());
                            var line = string.Join(",", cells);
                            writer.WriteLine(line);
                        }
                    }
                }
            }
            catch (Exception error)
            {
                MessageBox.Show("Error al convertir el archivo a CSV: " + error.Message);
            }
        }

        //Método para lectura de puerto serie
        private void SP1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                string data = SP1.ReadLine();

                if (data.Contains("Movimiento detectado"))
                {
                    LogAlert("Movimiento detectado");
                }
                else if (data.Contains("Motor endendido"))
                {
                    LogAlert("Motor encendido");
                }
                else if (data.Contains("Motor apagado"))
                {
                    LogAlert("Motor apagado");
                }
                else if (data.Contains("Conexión establecida"))
                {
                    LogAlert("Conexión establecida");
                }
                else if (data.Contains("Desconexion"))
                {
                    LogAlert("Desconexión del puerto COM");
                }
                else
                {
                    LogAlert("Dato recibido: " + data);
                }
            }
            catch (Exception error)
            {
                MessageBox.Show("Error al leer datos del puerto serie: " + error.Message);
                LogAlert("Error al leer datos del puerto serie: " + error.Message);
            }
        }
    }
}
错误分析与修正建议

1. XLSX文件保存路径错误

原代码中workbook.SaveAs("RegistroGimb.xlsx");未指定桌面路径,会将XLSX文件保存到程序运行目录(如bin/Debug),而非桌面。后续ConvertXlsxToCsv尝试从桌面路径读取该文件,必然找不到,导致转换失败。

修正:保存XLSX时指定桌面路径:

string xlsxPath = Path.Combine(desktopPath, "RegistroGimb.xlsx");
workbook.SaveAs(xlsxPath);

2. 转换CSV时参数传递错误

调用ConvertXlsxToCsv(filePath, csvFilePath);时,filePath是桌面的CSV路径,但实际要读取的是刚保存的XLSX文件,路径不匹配。

修正:传入正确的XLSX路径:

ConvertXlsxToCsv(xlsxPath, csvFilePath);

3. 字符串插值未生效

MessageBox.Show("Registro de alertas guardado en {filePath}");未使用$符号做字符串插值,会直接显示{filePath}而非实际路径。

修正:

MessageBox.Show($"Registro de alertas guardado en {csvFilePath}");

4. 串口数据重复处理

构造函数中同时绑定了SP1_DataReceived和DataReceivedHandler两个SerialDataReceived事件,会导致串口数据被两次读取、日志重复记录。

修正:移除其中一个事件绑定,保留SP1_DataReceived即可(该方法已包含日志记录逻辑):

// 移除这一行
// SP1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

5. 冗余的XLSX转CSV流程

直接将receivedDataList写入CSV即可,无需先存XLSX再转换,既浪费资源又增加出错概率。

简化后的SaveDataToCsv方法:

private void SaveDataToCsv()
{
    try
    {
        string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
        string csvFilePath = Path.Combine(desktopPath, "RegistroGimb.csv");

        // 直接写入CSV,跳过XLSX步骤
        using (var writer = new StreamWriter(csvFilePath))
        {
            writer.WriteLine("Registro de Actividades");
            foreach (var item in receivedDataList)
            {
                // 如果内容包含逗号,用引号包裹避免CSV格式错误
                var formattedLine = item.Contains(",") ? $"\"{item}\"" : item;
                writer.WriteLine(formattedLine);
            }
        }

        MessageBox.Show($"Registro de alertas guardado en {csvFilePath}");
    }
    catch (Exception error)
    {
        MessageBox.Show("Error al escribir en el archivo de registro: " + error.Message);
    }
}

同时可以删除ConvertXlsxToCsv方法和ClosedXML.Excel的引用,减少依赖。


内容的提问来源于stack exchange,提问作者Marshall

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 03:24:56