文章目录

概要

解决百万级数据导出导致内存溢出问题,之前的方式是把所有数据查询出来,然后循环所有数据插入到文件中上传到云上,这样数据少还行,数据多了内存就溢出了。

解决方案

直接重构代码:使用ADO的SqlDataReader获取数据,这样避免把所有数据加载到内存中(具体工作原理有兴趣的可以去百度下),导出excel使用NPOI的SXSSFWorkbook,用于处理大型 Excel 文件的一个类,它是 XSSFWorkbook 的流式版本,专门用于高效处理大数据量的 Excel 文件,避免内存溢出,下面直接上代码。

class Program1
{
    static void Main()
    {
        string connectionString = "your_connection_string";
        string query = "SELECT Name, Age FROM Users";
        string SheetName = "sheet1";
        List<string> column = new List<string>();
        column.Add("Name");
        column.Add("Age");
        SXSSFWorkbook book = new SXSSFWorkbook();
        var sheet = book.CreateSheet(SheetName);

        using (var connection = new SqlConnection(connectionString))
        {
            connection.Open();
            // 使用 SqlCommand 和 SqlDataReader 以流式方式读取数据
            using (var command = new SqlCommand(query, connection))
            {
                using (var reader = command.ExecuteReader())
                {
                    int rowCount = 1;
                    while (reader.Read())
                    {
                        var row = sheet.CreateRow(rowCount);
                        //计数
                        int count = 0;
                        foreach (var co in column)
                        {
                            var cell = row.CreateCell(count);
                            int columnIndex = reader.GetOrdinal(co);//获取对应字段的索引
                            string columnType = reader.GetFieldType(columnIndex).Name;//根据索引获取字段类型
                            var val = reader[columnIndex];//根据索引获取对应的值
                            if (val == null || val == DBNull.Value || string.IsNullOrWhiteSpace(val?.ToString()))
                            {
                                cell.SetCellValue("");
                                count++;
                                continue;
                            }

                            if (!string.IsNullOrWhiteSpace(columnType))
                            {
                                if (columnType.Equals("date", StringComparison.OrdinalIgnoreCase) || columnType.Equals("dateTime", StringComparison.OrdinalIgnoreCase))
                                {
                                    try
                                    {
                                        //时间转换
                                        DateTime dt;
                                        var flag = DateTime.TryParse(val.ToString(), out dt);
                                        if (flag)
                                        {
                                            val = dt;
                                        }
                                        cell.SetCellValue(val.ToString());
                                    }
                                    catch
                                    {
                                        cell.SetCellValue(Convert.ToString(val));
                                    }

                                }
                                else if (columnType.Equals("decimal", StringComparison.OrdinalIgnoreCase))
                                {
                                    try
                                    {
                                        cell.SetCellValue(Convert.ToDouble(Math.Round(Convert.ToDouble(val), 2)));
                                    }
                                    catch
                                    {
                                        cell.SetCellValue(Convert.ToString(val));
                                    }
                                }
                                else
                                {
                                    cell.SetCellValue(Convert.ToString(val));
                                }

                            }
                            else
                            {
                                cell.SetCellValue(Convert.ToString(val));
                            }
                            count++;
                        }
                        rowCount++;
                    }
                }
            }
        }
        // 1. 创建临时文件路径
        string filePath = Path.GetTempFileName();
        // 直接写入文件流,避免内存溢出
        using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
        {
            book.Write(fs); // 直接写入文件
            book.Close();
            book.Dispose();
        }

        //上传文件
        var storage = GetStorageService();
        using (FileStream fileStream = File.OpenRead(filePath))
        {
            var uploadResult = storage.UploadFile(fileStream, fileName);
        }
        File.Delete(filePath);
    }
}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐