C#讀取CSV/Excel文件數(shù)據(jù)并顯示在DataGridView
C# 用于讀取 CSV 和 Excel 文件數(shù)據(jù)并顯示在 DataGridView 控件中,支持文件選擇、數(shù)據(jù)預(yù)覽、格式處理和錯誤處理等功能。
解決方案結(jié)構(gòu)
CsvExcelReader/ ├── CsvExcelReader.sln ├── CsvExcelReader/ │ ├── App.config │ ├── Form1.cs │ ├── Form1.Designer.cs │ ├── Form1.resx │ ├── Program.cs │ ├── FileReader.cs │ ├── DataProcessor.cs │ └── Properties/ │ ├── AssemblyInfo.cs │ └── Resources.Designer.cs └── packages.config
完整代碼實現(xiàn)
1. 主窗體 (Form1.cs)
using System;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.HSSF.UserModel;
namespace CsvExcelReader
{
public partial class MainForm : Form
{
private readonly FileReader fileReader = new FileReader();
private readonly DataProcessor dataProcessor = new DataProcessor();
public MainForm()
{
InitializeComponent();
InitializeUI();
}
private void InitializeUI()
{
// 窗體設(shè)置
this.Text = "CSV/Excel 數(shù)據(jù)讀取器";
this.Size = new Size(900, 600);
this.StartPosition = FormStartPosition.CenterScreen;
this.BackColor = Color.FromArgb(240, 240, 240);
// 創(chuàng)建控件
lblTitle = new Label
{
Text = "CSV/Excel 數(shù)據(jù)讀取器",
Font = new Font("微軟雅黑", 16, FontStyle.Bold),
ForeColor = Color.DarkSlateBlue,
AutoSize = true,
Location = new Point(20, 20)
};
btnOpenCsv = new Button
{
Text = "打開 CSV 文件",
Size = new Size(120, 40),
Location = new Point(30, 70),
BackColor = Color.SteelBlue,
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Font = new Font("微軟雅黑", 10)
};
btnOpenCsv.FlatAppearance.BorderSize = 0;
btnOpenCsv.Click += BtnOpenCsv_Click;
btnOpenExcel = new Button
{
Text = "打開 Excel 文件",
Size = new Size(120, 40),
Location = new Point(160, 70),
BackColor = Color.ForestGreen,
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Font = new Font("微軟雅黑", 10)
};
btnOpenExcel.FlatAppearance.BorderSize = 0;
btnOpenExcel.Click += BtnOpenExcel_Click;
btnSaveCsv = new Button
{
Text = "保存為 CSV",
Size = new Size(120, 40),
Location = new Point(290, 70),
BackColor = Color.Orange,
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Font = new Font("微軟雅黑", 10),
Enabled = false
};
btnSaveCsv.FlatAppearance.BorderSize = 0;
btnSaveCsv.Click += BtnSaveCsv_Click;
btnSaveExcel = new Button
{
Text = "保存為 Excel",
Size = new Size(120, 40),
Location = new Point(420, 70),
BackColor = Color.Purple,
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Font = new Font("微軟雅黑", 10),
Enabled = false
};
btnSaveExcel.FlatAppearance.BorderSize = 0;
btnSaveExcel.Click += BtnSaveExcel_Click;
btnClear = new Button
{
Text = "清除數(shù)據(jù)",
Size = new Size(120, 40),
Location = new Point(550, 70),
BackColor = Color.Gray,
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Font = new Font("微軟雅黑", 10)
};
btnClear.FlatAppearance.BorderSize = 0;
btnClear.Click += BtnClear_Click;
// 狀態(tài)標簽
lblStatus = new Label
{
Text = "就緒",
AutoSize = true,
Location = new Point(30, 120),
Font = new Font("微軟雅黑", 9),
ForeColor = Color.DimGray
};
// 數(shù)據(jù)網(wǎng)格視圖
dataGridView = new DataGridView
{
Location = new Point(20, 150),
Size = new Size(840, 400),
BackgroundColor = Color.White,
BorderStyle = BorderStyle.FixedSingle,
AllowUserToAddRows = false,
AllowUserToDeleteRows = false,
ReadOnly = true,
AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells,
RowHeadersVisible = false,
ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle
{
BackColor = Color.SteelBlue,
ForeColor = Color.White,
Font = new Font("微軟雅黑", 10, FontStyle.Bold)
},
DefaultCellStyle = new DataGridViewCellStyle
{
Font = new Font("微軟雅黑", 9),
SelectionBackColor = Color.LightSteelBlue
},
EnableHeadersVisualStyles = false
};
// 進度條
progressBar = new ProgressBar
{
Location = new Point(20, 560),
Size = new Size(840, 20),
Visible = false
};
// 添加控件到窗體
this.Controls.Add(lblTitle);
this.Controls.Add(btnOpenCsv);
this.Controls.Add(btnOpenExcel);
this.Controls.Add(btnSaveCsv);
this.Controls.Add(btnSaveExcel);
this.Controls.Add(btnClear);
this.Controls.Add(lblStatus);
this.Controls.Add(dataGridView);
this.Controls.Add(progressBar);
}
#region 控件聲明
private Label lblTitle;
private Button btnOpenCsv;
private Button btnOpenExcel;
private Button btnSaveCsv;
private Button btnSaveExcel;
private Button btnClear;
private Label lblStatus;
private DataGridView dataGridView;
private ProgressBar progressBar;
#endregion
#region 事件處理
private void BtnOpenCsv_Click(object sender, EventArgs e)
{
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "CSV 文件 (*.csv)|*.csv|所有文件 (*.*)|*.*";
openFileDialog.Title = "選擇 CSV 文件";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
LoadFile(openFileDialog.FileName, FileType.Csv);
}
}
}
private void BtnOpenExcel_Click(object sender, EventArgs e)
{
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "Excel 文件 (*.xls;*.xlsx)|*.xls;*.xlsx|所有文件 (*.*)|*.*";
openFileDialog.Title = "選擇 Excel 文件";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
LoadFile(openFileDialog.FileName, FileType.Excel);
}
}
}
private void BtnSaveCsv_Click(object sender, EventArgs e)
{
if (dataGridView.DataSource == null) return;
using (SaveFileDialog saveFileDialog = new SaveFileDialog())
{
saveFileDialog.Filter = "CSV 文件 (*.csv)|*.csv";
saveFileDialog.Title = "保存為 CSV 文件";
saveFileDialog.FileName = "data_export.csv";
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
try
{
dataProcessor.ExportToCsv((DataTable)dataGridView.DataSource, saveFileDialog.FileName);
lblStatus.Text = $"數(shù)據(jù)已成功導(dǎo)出到: {saveFileDialog.FileName}";
}
catch (Exception ex)
{
MessageBox.Show($"導(dǎo)出失敗: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
private void BtnSaveExcel_Click(object sender, EventArgs e)
{
if (dataGridView.DataSource == null) return;
using (SaveFileDialog saveFileDialog = new SaveFileDialog())
{
saveFileDialog.Filter = "Excel 文件 (*.xlsx)|*.xlsx";
saveFileDialog.Title = "保存為 Excel 文件";
saveFileDialog.FileName = "data_export.xlsx";
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
try
{
dataProcessor.ExportToExcel((DataTable)dataGridView.DataSource, saveFileDialog.FileName);
lblStatus.Text = $"數(shù)據(jù)已成功導(dǎo)出到: {saveFileDialog.FileName}";
}
catch (Exception ex)
{
MessageBox.Show($"導(dǎo)出失敗: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
private void BtnClear_Click(object sender, EventArgs e)
{
dataGridView.DataSource = null;
btnSaveCsv.Enabled = false;
btnSaveExcel.Enabled = false;
lblStatus.Text = "數(shù)據(jù)已清除";
}
#endregion
#region 文件加載與處理
private void LoadFile(string filePath, FileType fileType)
{
try
{
progressBar.Visible = true;
progressBar.Style = ProgressBarStyle.Marquee;
lblStatus.Text = $"正在加載文件: {Path.GetFileName(filePath)}...";
Application.DoEvents();
DataTable dataTable = fileType == FileType.Csv
? fileReader.ReadCsv(filePath)
: fileReader.ReadExcel(filePath);
if (dataTable == null || dataTable.Rows.Count == 0)
{
lblStatus.Text = "文件為空或未找到數(shù)據(jù)";
return;
}
// 數(shù)據(jù)預(yù)處理
dataTable = dataProcessor.ProcessDataTable(dataTable);
// 綁定到DataGridView
dataGridView.DataSource = dataTable;
// 啟用保存按鈕
btnSaveCsv.Enabled = true;
btnSaveExcel.Enabled = true;
lblStatus.Text = $"已加載: {Path.GetFileName(filePath)} | 行: {dataTable.Rows.Count} | 列: {dataTable.Columns.Count}";
}
catch (Exception ex)
{
MessageBox.Show($"加載文件失敗: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
lblStatus.Text = $"錯誤: {ex.Message}";
}
finally
{
progressBar.Visible = false;
}
}
#endregion
}
public enum FileType
{
Csv,
Excel
}
}
2. 文件讀取器 (FileReader.cs)
using System;
using System.Data;
using System.IO;
using System.Text;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.HSSF.UserModel;
namespace CsvExcelReader
{
public class FileReader
{
/// <summary>
/// 讀取CSV文件并返回DataTable
/// </summary>
public DataTable ReadCsv(string filePath)
{
if (!File.Exists(filePath))
throw new FileNotFoundException("文件不存在", filePath);
DataTable dataTable = new DataTable();
int rowCount = 0;
using (var reader = new StreamReader(filePath, Encoding.UTF8))
{
string line;
bool isFirstRow = true;
while ((line = reader.ReadLine()) != null)
{
// 處理可能的引號包圍字段
string[] fields = ParseCsvLine(line);
if (isFirstRow)
{
// 創(chuàng)建列
foreach (string field in fields)
{
dataTable.Columns.Add(field);
}
isFirstRow = false;
}
else
{
// 添加行數(shù)據(jù)
if (fields.Length > dataTable.Columns.Count)
{
// 添加缺失的列
for (int i = dataTable.Columns.Count; i < fields.Length; i++)
{
dataTable.Columns.Add($"Column{dataTable.Columns.Count + 1}");
}
}
DataRow row = dataTable.NewRow();
for (int i = 0; i < fields.Length; i++)
{
if (i < dataTable.Columns.Count)
{
row[i] = fields[i];
}
}
dataTable.Rows.Add(row);
}
rowCount++;
}
}
return dataTable;
}
/// <summary>
/// 解析CSV行,處理逗號和引號
/// </summary>
private string[] ParseCsvLine(string line)
{
var fields = new System.Collections.Generic.List<string>();
bool inQuotes = false;
var currentField = new StringBuilder();
for (int i = 0; i < line.Length; i++)
{
char c = line[i];
if (c == '"')
{
// 處理轉(zhuǎn)義引號
if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
{
currentField.Append('"');
i++;
}
else
{
inQuotes = !inQuotes;
}
}
else if (c == ',' && !inQuotes)
{
// 字段結(jié)束
fields.Add(currentField.ToString());
currentField.Clear();
}
else
{
currentField.Append(c);
}
}
// 添加最后一個字段
fields.Add(currentField.ToString());
return fields.ToArray();
}
/// <summary>
/// 讀取Excel文件并返回DataTable
/// </summary>
public DataTable ReadExcel(string filePath)
{
if (!File.Exists(filePath))
throw new FileNotFoundException("文件不存在", filePath);
IWorkbook workbook;
DataTable dataTable = new DataTable();
int rowCount = 0;
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
// 根據(jù)擴展名創(chuàng)建不同的工作簿
if (Path.GetExtension(filePath).Equals(".xlsx", StringComparison.OrdinalIgnoreCase))
{
workbook = new XSSFWorkbook(fileStream);
}
else if (Path.GetExtension(filePath).Equals(".xls", StringComparison.OrdinalIgnoreCase))
{
workbook = new HSSFWorkbook(fileStream);
}
else
{
throw new NotSupportedException("不支持的Excel文件格式");
}
// 獲取第一個工作表
ISheet sheet = workbook.GetSheetAt(0);
if (sheet == null) return dataTable;
// 獲取標題行
IRow headerRow = sheet.GetRow(0);
if (headerRow == null) return dataTable;
// 創(chuàng)建列
for (int i = 0; i < headerRow.LastCellNum; i++)
{
ICell cell = headerRow.GetCell(i);
string columnName = cell?.ToString() ?? $"Column{i + 1}";
dataTable.Columns.Add(columnName);
}
// 添加數(shù)據(jù)行
for (int i = 1; i <= sheet.LastRowNum; i++)
{
IRow row = sheet.GetRow(i);
if (row == null) continue;
DataRow dataRow = dataTable.NewRow();
for (int j = 0; j < dataTable.Columns.Count; j++)
{
ICell cell = row.GetCell(j);
if (cell != null)
{
switch (cell.CellType)
{
case CellType.String:
dataRow[j] = cell.StringCellValue;
break;
case CellType.Numeric:
if (DateUtil.IsCellDateFormatted(cell))
{
dataRow[j] = cell.DateCellValue.ToString("yyyy-MM-dd");
}
else
{
dataRow[j] = cell.NumericCellValue;
}
break;
case CellType.Boolean:
dataRow[j] = cell.BooleanCellValue;
break;
case CellType.Formula:
dataRow[j] = cell.NumericCellValue;
break;
default:
dataRow[j] = cell.ToString();
break;
}
}
}
dataTable.Rows.Add(dataRow);
rowCount++;
}
}
return dataTable;
}
}
}
3. 數(shù)據(jù)處理類 (DataProcessor.cs)
using System;
using System.Data;
using System.Globalization;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.HSSF.UserModel;
namespace CsvExcelReader
{
public class DataProcessor
{
/// <summary>
/// 處理DataTable數(shù)據(jù)(類型轉(zhuǎn)換、空值處理等)
/// </summary>
public DataTable ProcessDataTable(DataTable inputTable)
{
if (inputTable == null) return null;
DataTable processedTable = inputTable.Clone();
// 處理列數(shù)據(jù)類型
foreach (DataColumn column in processedTable.Columns)
{
// 嘗試推斷列的數(shù)據(jù)類型
Type inferredType = InferColumnType(inputTable, column.ColumnName);
if (inferredType != null)
{
column.DataType = inferredType;
}
}
// 處理行數(shù)據(jù)
foreach (DataRow row in inputTable.Rows)
{
DataRow newRow = processedTable.NewRow();
for (int i = 0; i < inputTable.Columns.Count; i++)
{
string columnName = inputTable.Columns[i].ColumnName;
object value = row[i];
// 處理空值
if (value == null || value == DBNull.Value || string.IsNullOrWhiteSpace(value.ToString()))
{
newRow[columnName] = DBNull.Value;
continue;
}
// 處理數(shù)值類型
if (processedTable.Columns[columnName].DataType == typeof(int))
{
if (int.TryParse(value.ToString(), out int intValue))
{
newRow[columnName] = intValue;
}
else
{
newRow[columnName] = DBNull.Value;
}
}
else if (processedTable.Columns[columnName].DataType == typeof(double))
{
if (double.TryParse(value.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out double doubleValue))
{
newRow[columnName] = doubleValue;
}
else
{
newRow[columnName] = DBNull.Value;
}
}
else if (processedTable.Columns[columnName].DataType == typeof(DateTime))
{
if (DateTime.TryParse(value.ToString(), out DateTime dateValue))
{
newRow[columnName] = dateValue;
}
else
{
newRow[columnName] = DBNull.Value;
}
}
else
{
newRow[columnName] = value.ToString().Trim();
}
}
processedTable.Rows.Add(newRow);
}
return processedTable;
}
/// <summary>
/// 推斷列的數(shù)據(jù)類型
/// </summary>
private Type InferColumnType(DataTable table, string columnName)
{
int totalRows = table.Rows.Count;
if (totalRows == 0) return typeof(string);
int intCount = 0;
int doubleCount = 0;
int dateCount = 0;
int stringCount = 0;
foreach (DataRow row in table.Rows)
{
object value = row[columnName];
if (value == null || value == DBNull.Value) continue;
string strValue = value.ToString().Trim();
if (string.IsNullOrEmpty(strValue)) continue;
if (int.TryParse(strValue, out _))
{
intCount++;
}
else if (double.TryParse(strValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
{
doubleCount++;
}
else if (DateTime.TryParse(strValue, out _))
{
dateCount++;
}
else
{
stringCount++;
}
}
// 如果80%以上的值都是整數(shù),則認為是整數(shù)類型
if ((double)intCount / totalRows > 0.8) return typeof(int);
// 如果80%以上的值都是浮點數(shù),則認為是浮點數(shù)類型
if ((double)(intCount + doubleCount) / totalRows > 0.8) return typeof(double);
// 如果80%以上的值都是日期,則認為是日期類型
if ((double)dateCount / totalRows > 0.8) return typeof(DateTime);
return typeof(string);
}
/// <summary>
/// 導(dǎo)出DataTable到CSV文件
/// </summary>
public void ExportToCsv(DataTable dataTable, string filePath)
{
if (dataTable == null) return;
using (var writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
// 寫入列頭
for (int i = 0; i < dataTable.Columns.Count; i++)
{
writer.Write(EscapeCsvField(dataTable.Columns[i].ColumnName));
if (i < dataTable.Columns.Count - 1)
{
writer.Write(",");
}
}
writer.WriteLine();
// 寫入數(shù)據(jù)行
foreach (DataRow row in dataTable.Rows)
{
for (int i = 0; i < dataTable.Columns.Count; i++)
{
object value = row[i];
string strValue = value?.ToString() ?? string.Empty;
writer.Write(EscapeCsvField(strValue));
if (i < dataTable.Columns.Count - 1)
{
writer.Write(",");
}
}
writer.WriteLine();
}
}
}
/// <summary>
/// 轉(zhuǎn)義CSV字段
/// </summary>
private string EscapeCsvField(string field)
{
if (string.IsNullOrEmpty(field)) return string.Empty;
// 如果包含逗號、換行符或雙引號,則用雙引號包圍
if (field.Contains(",") || field.Contains("\"") || field.Contains("\n") || field.Contains("\r"))
{
return "\"" + field.Replace("\"", "\"\"") + "\"";
}
return field;
}
/// <summary>
/// 導(dǎo)出DataTable到Excel文件
/// </summary>
public void ExportToExcel(DataTable dataTable, string filePath)
{
if (dataTable == null) return;
IWorkbook workbook;
if (Path.GetExtension(filePath).Equals(".xlsx", StringComparison.OrdinalIgnoreCase))
{
workbook = new XSSFWorkbook();
}
else
{
workbook = new HSSFWorkbook();
}
ISheet sheet = workbook.CreateSheet("Sheet1");
// 創(chuàng)建標題行
IRow headerRow = sheet.CreateRow(0);
for (int i = 0; i < dataTable.Columns.Count; i++)
{
ICell cell = headerRow.CreateCell(i);
cell.SetCellValue(dataTable.Columns[i].ColumnName);
// 設(shè)置標題樣式
ICellStyle style = workbook.CreateCellStyle();
IFont font = workbook.CreateFont();
font.Boldweight = (short)FontBoldWeight.Bold;
style.SetFont(font);
cell.CellStyle = style;
}
// 填充數(shù)據(jù)
for (int i = 0; i < dataTable.Rows.Count; i++)
{
IRow row = sheet.CreateRow(i + 1);
for (int j = 0; j < dataTable.Columns.Count; j++)
{
ICell cell = row.CreateCell(j);
object value = dataTable.Rows[i][j];
if (value == DBNull.Value || value == null)
{
cell.SetCellValue(string.Empty);
}
else if (value is int intValue)
{
cell.SetCellValue(intValue);
}
else if (value is double doubleValue)
{
cell.SetCellValue(doubleValue);
}
else if (value is DateTime dateValue)
{
cell.SetCellValue(dateValue);
ICellStyle dateStyle = workbook.CreateCellStyle();
IDataFormat format = workbook.CreateDataFormat();
dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd");
cell.CellStyle = dateStyle;
}
else
{
cell.SetCellValue(value.ToString());
}
}
}
// 自動調(diào)整列寬
for (int i = 0; i < dataTable.Columns.Count; i++)
{
sheet.AutoSizeColumn(i);
}
// 保存文件
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(fileStream);
}
}
}
}
4. 程序入口 (Program.cs)
using System;
using System.Windows.Forms;
namespace CsvExcelReader
{
static class Program
{
/// <summary>
/// 應(yīng)用程序的主入口點。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
5. 應(yīng)用程序配置文件 (App.config)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="NPOI" publicKeyToken="0DF73EC7942D9264" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.5.6.0" newVersion="2.5.6.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NPOI.OOXML" publicKeyToken="0DF73EC7942D9264" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.5.6.0" newVersion="2.5.6.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NPOI.HPSF" publicKeyToken="0DF73EC7942D9264" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.5.6.0" newVersion="2.5.6.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>6. NuGet 包配置 (packages.config)
<?xml version="1.0" encoding="utf-8"?> <packages> <package id="NPOI" version="2.5.6" targetFramework="net472" /> <package id="NPOI.OOXML" version="2.5.6" targetFramework="net472" /> <package id="NPOI.HPSF" version="2.5.6" targetFramework="net472" /> </packages>
功能特點
1. 文件讀取功能
CSV文件:
- 支持逗號分隔的標準CSV格式
- 自動處理引號包圍的字段
- 支持包含逗號的字段內(nèi)容
- 自動檢測列頭和創(chuàng)建數(shù)據(jù)結(jié)構(gòu)
Excel文件:
- 支持.xls和.xlsx格式
- 自動識別第一個工作表
- 智能數(shù)據(jù)類型識別(文本、數(shù)值、日期)
- 處理合并單元格和公式
2. 數(shù)據(jù)處理功能
數(shù)據(jù)類型推斷:
- 自動識別整數(shù)、浮點數(shù)、日期和文本
- 基于數(shù)據(jù)分布智能判斷最佳類型
數(shù)據(jù)清洗:
- 自動去除多余空格
- 處理空值和DBNull
- 格式化日期和數(shù)字
錯誤處理:
- 捕獲并顯示文件讀取錯誤
- 處理格式不正確的數(shù)據(jù)行
- 提供詳細的錯誤信息
3. 用戶界面功能
直觀的操作界面:
- 清晰的按鈕布局
- 狀態(tài)提示和進度指示
- 響應(yīng)式設(shè)計
數(shù)據(jù)預(yù)覽:
- 自動調(diào)整列寬
- 交替行顏色提高可讀性
- 支持滾動查看大數(shù)據(jù)集
數(shù)據(jù)導(dǎo)出:
- 一鍵導(dǎo)出為CSV或Excel
- 保留數(shù)據(jù)類型和格式
- 自動命名導(dǎo)出文件
4. 性能優(yōu)化
流式讀取:
- 大文件分塊處理
- 內(nèi)存高效的數(shù)據(jù)加載
后臺處理:
- 進度條顯示加載狀態(tài)
- 異步操作防止界面凍結(jié)
資源管理:
- 及時釋放文件句柄
- 使用using語句確保資源釋放
使用說明
1. 環(huán)境要求
.NET Framework 4.7.2 或更高版本
安裝NuGet包:
Install-Package NPOI Install-Package NPOI.OOXML Install-Package NPOI.HPSF
2. 操作步驟
打開文件:
- 點擊"打開CSV文件"按鈕選擇CSV文件
- 點擊"打開Excel文件"按鈕選擇Excel文件
查看數(shù)據(jù):
- 文件加載后顯示在DataGridView中
- 自動識別數(shù)據(jù)類型并顯示
- 可通過滾動條查看所有數(shù)據(jù)
導(dǎo)出數(shù)據(jù):
- 加載數(shù)據(jù)后導(dǎo)出按鈕啟用
- 點擊"保存為CSV"導(dǎo)出為CSV格式
- 點擊"保存為Excel"導(dǎo)出為Excel格式
清除數(shù)據(jù):
- 點擊"清除數(shù)據(jù)"按鈕清空當(dāng)前顯示
3. 使用示例
// 示例:在代碼中直接使用讀取器 var reader = new FileReader(); // 讀取CSV文件 DataTable csvData = reader.ReadCsv(@"C:\data\sales.csv"); // 讀取Excel文件 DataTable excelData = reader.ReadExcel(@"C:\data\inventory.xlsx"); // 處理數(shù)據(jù) var processor = new DataProcessor(); DataTable processedData = processor.ProcessDataTable(csvData); // 導(dǎo)出數(shù)據(jù) processor.ExportToCsv(processedData, @"C:\output\processed.csv"); processor.ExportToExcel(processedData, @"C:\output\processed.xlsx");
技術(shù)亮點
1. CSV解析算法
private string[] ParseCsvLine(string line)
{
var fields = new List<string>();
bool inQuotes = false;
var currentField = new StringBuilder();
for (int i = 0; i < line.Length; i++)
{
char c = line[i];
if (c == '"')
{
// 處理轉(zhuǎn)義引號
if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
{
currentField.Append('"');
i++;
}
else
{
inQuotes = !inQuotes;
}
}
else if (c == ',' && !inQuotes)
{
// 字段結(jié)束
fields.Add(currentField.ToString());
currentField.Clear();
}
else
{
currentField.Append(c);
}
}
// 添加最后一個字段
fields.Add(currentField.ToString());
return fields.ToArray();
}
2. Excel數(shù)據(jù)類型處理
switch (cell.CellType)
{
case CellType.String:
dataRow[j] = cell.StringCellValue;
break;
case CellType.Numeric:
if (DateUtil.IsCellDateFormatted(cell))
{
dataRow[j] = cell.DateCellValue.ToString("yyyy-MM-dd");
}
else
{
dataRow[j] = cell.NumericCellValue;
}
break;
case CellType.Boolean:
dataRow[j] = cell.BooleanCellValue;
break;
case CellType.Formula:
dataRow[j] = cell.NumericCellValue;
break;
default:
dataRow[j] = cell.ToString();
break;
}
3. 數(shù)據(jù)類型推斷
private Type InferColumnType(DataTable table, string columnName)
{
int totalRows = table.Rows.Count;
if (totalRows == 0) return typeof(string);
int intCount = 0;
int doubleCount = 0;
int dateCount = 0;
int stringCount = 0;
foreach (DataRow row in table.Rows)
{
// 分析每個值的類型...
}
// 根據(jù)分布確定最佳類型
if ((double)intCount / totalRows > 0.8) return typeof(int);
if ((double)(intCount + doubleCount) / totalRows > 0.8) return typeof(double);
if ((double)dateCount / totalRows > 0.8) return typeof(DateTime);
return typeof(string);
}
擴展功能
1. 添加數(shù)據(jù)庫支持
public class DatabaseExporter
{
public void ExportToSqlServer(DataTable data, string connectionString, string tableName)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
{
bulkCopy.DestinationTableName = tableName;
// 映射列
foreach (DataColumn column in data.Columns)
{
bulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
bulkCopy.WriteToServer(data);
}
}
}
}
2. 添加數(shù)據(jù)過濾功能
public DataTable FilterData(DataTable data, string columnName, string filterValue)
{
DataView dv = new DataView(data);
dv.RowFilter = $"[{columnName}] LIKE '%{filterValue}%'";
return dv.ToTable();
}
3. 添加數(shù)據(jù)統(tǒng)計功能
public DataTable GetSummaryStatistics(DataTable data)
{
DataTable summary = new DataTable();
summary.Columns.Add("Column", typeof(string));
summary.Columns.Add("Type", typeof(string));
summary.Columns.Add("Count", typeof(int));
summary.Columns.Add("NullCount", typeof(int));
summary.Columns.Add("Min", typeof(string));
summary.Columns.Add("Max", typeof(string));
summary.Columns.Add("Avg", typeof(string));
foreach (DataColumn column in data.Columns)
{
DataRow row = summary.NewRow();
row["Column"] = column.ColumnName;
row["Type"] = column.DataType.Name;
int count = data.Rows.Count;
int nullCount = 0;
double? min = null, max = null, sum = 0;
int numericCount = 0;
foreach (DataRow dataRow in data.Rows)
{
object value = dataRow[column];
if (value == DBNull.Value || value == null)
{
nullCount++;
continue;
}
if (column.DataType == typeof(int) || column.DataType == typeof(double))
{
double numValue = Convert.ToDouble(value);
if (!min.HasValue || numValue < min) min = numValue;
if (!max.HasValue || numValue > max) max = numValue;
sum += numValue;
numericCount++;
}
}
row["Count"] = count;
row["NullCount"] = nullCount;
row["Min"] = min?.ToString() ?? "N/A";
row["Max"] = max?.ToString() ?? "N/A";
row["Avg"] = numericCount > 0 ? (sum / numericCount).ToString() : "N/A";
summary.Rows.Add(row);
}
return summary;
}
常見問題解決
1. 文件格式問題
問題:中文亂碼
解決:在讀取CSV時指定正確的編碼
// 嘗試不同編碼
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
using (var reader = new StreamReader(filePath, Encoding.GetEncoding("GB2312")))
2. 大文件處理
問題:加載大文件時內(nèi)存不足
解決:使用分頁加載
// 分批讀取大文件
public DataTable ReadLargeCsv(string filePath, int batchSize = 1000)
{
// 實現(xiàn)分頁讀取邏輯
}
3. 特殊格式處理
問題:Excel中的公式值
解決:使用NPOI的公式求值器
IFormulaEvaluator evaluator = workbook.GetCreationHelper().CreateFormulaEvaluator(); CellValue cellValue = evaluator.Evaluate(cell);
項目總結(jié)
這個C#解決方案提供了完整的CSV/Excel文件讀取和顯示功能,具有以下特點:
多格式支持:
- 支持CSV和Excel文件(.xls/.xlsx)
- 智能識別文件格式
- 處理各種數(shù)據(jù)格式和編碼
強大的數(shù)據(jù)處理:
- 自動數(shù)據(jù)類型推斷
- 數(shù)據(jù)清洗和轉(zhuǎn)換
- 空值處理和錯誤恢復(fù)
用戶友好界面:
- 直觀的操作流程
- 實時狀態(tài)反饋
- 響應(yīng)式數(shù)據(jù)展示
靈活的導(dǎo)出功能:
- 支持CSV和Excel導(dǎo)出
- 保留數(shù)據(jù)類型和格式
- 自定義導(dǎo)出選項
健壯的錯誤處理:
- 全面的異常捕獲
- 詳細的錯誤信息
- 優(yōu)雅的降級處理
以上就是C#讀取CSV/Excel文件數(shù)據(jù)并顯示在DataGridView的詳細內(nèi)容,更多關(guān)于C#讀取CSV/Excel數(shù)據(jù)并顯示的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#中的modbus Tcp協(xié)議的數(shù)據(jù)抓取和使用解析
這篇文章主要介紹了C#中的modbus Tcp協(xié)議的數(shù)據(jù)抓取和使用解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07

