【问题标题】:Download EXCEL file from ASP.NET page without Generating physical file on server (On The Fly)从 ASP.NET 页面下载 EXCEL 文件,而不在服务器上生成物理文件(即时)
【发布时间】:2012-05-16 23:33:48
【问题描述】:

我正在尝试使用 Microsoft Office EXCEL INTEROP 将 C# DataTable 动态导出到 EXCEL 文件(不创建物理文件),并通过 Response 对象通过 asp.net 网页下载它。我可以使用库生成内存流但是不知何故,文件没有通过内存流保存。参考代码如下。您需要参考 DocumentFormat.OpenXml.dll 和 WindowsBase.DLL(您可以从微软网站下载)。

任何想法如何解决这个问题? ? ?

Private void DownloadFile()
{
                DataSet objTable = ReadTableFromViewstate();
            if (objTable != null && objTable.Rows.Count > 0)
            {

                string strDownloadableFilename = "TestExcelFileName.xls";
                MemoryStream fs1 = new MemoryStream();
                if (CreateExcelFile.CreateExcelDocument(objTable, fs1))
                {
                    Response.Clear();
                        byte[] data1 = new byte[fs1.Length];
                        fs1.Read(data1, 0, data1.Length);
                        fs1.Close();

                    Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                    Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", strDownloadableFilename));
                    Response.BinaryWrite(data1); ;
                   Response.End();

                }
                else
                {
                    LblErrorMessage.Text = "Error Exporting File.";
                }
            }

        }

..

public static bool CreateExcelDocument(DataSet ds, System.IO.Stream excelFileStream)
    {
        try
        {
            using (SpreadsheetDocument document = SpreadsheetDocument.Create(excelFileStream, SpreadsheetDocumentType.Workbook))
            {
                CreateParts(ds, document);
            }

            Trace.WriteLine("Successfully created: " + excelFileStream);
            return true;
        }
        catch (Exception ex)
        {
            Trace.WriteLine("Failed, exception thrown: " + ex.Message);
            return false;
        }
    }
..




private static void CreateParts(DataSet ds, SpreadsheetDocument document)
        {
            WorkbookPart workbookPart = document.AddWorkbookPart();
            Workbook workbook = new Workbook();
            workbookPart.Workbook = workbook;

            //  If we don't add a "WorkbookStylesPart", OLEDB will refuse to connect to this .xlsx file !

                WorkbookStylesPart workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles");
            Stylesheet stylesheet = new Stylesheet();

            workbookStylesPart.Stylesheet = stylesheet;

            Sheets sheets = new Sheets();

            //  Loop through each of the DataTables in our DataSet, and create a new Excel Worksheet for each.
        uint worksheetNumber = 1;
        foreach (DataTable dt in ds.Tables)
        {
            //  For each worksheet you want to create
            string workSheetID = "rId" + worksheetNumber.ToString();
            string worksheetName = dt.TableName;

            WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>(workSheetID);
            WriteDataTableToExcelWorksheet(dt, worksheetPart);

            Sheet sheet = new Sheet() { Name = worksheetName, SheetId = (UInt32Value)worksheetNumber, Id = workSheetID };
            sheets.Append(sheet);

            worksheetNumber++;
        }

        workbook.Append(sheets);
    }

【问题讨论】:

  • 为什么不以制表符分隔,然后将其发送给用户?它将在 Excel 中打开。
  • 不是一个真正的答案,但我可以推荐 EPPLus 即时创建 Excel 文件。 stackoverflow.com/a/10547727/284240 那么你只需要Response.BinaryWrite(pck.GetAsByteArray());
  • @James:感谢您的建议。但我不想那样做,否则我可能会生成 .csv 文件。我想使用 INTEROP,因为将来我想将图像/图形添加到 excel 表中(这也是即时的)。
  • @Tim:感谢您的链接,图书馆似乎很有希望。 :-) 但我正在尝试开发相同类型的库。我使用的代码几乎与编写库的代码相同。我需要 ExcelDocument.GetAsByteArray() 方法的实现。 (即它如何从 INTEROP 返回的 Stream 对象转换为 ByteArray)
  • @Sankalp:您可以使用ILSpy 来反映代码。但请记住,它是LGPL。那么为什么不首先使用它呢?

标签: c# asp.net openxml office-interop openxml-sdk


【解决方案1】:

感谢大家,终于解决了我的问题。我刚刚替换了以下代码行:

                    byte[] data1 = new byte[fs1.Length];
                    fs1.Read(data1, 0, data1.Length);
                    fs1.Close();

这一行

                    byte[] data1 = fs1.ToArray();

我的问题得到了解决。

【讨论】:

    【解决方案2】:

    写完内存流后,需要将指针设置回原点,然后再读取。

    fs1.Seek(0, SeekOrigin.Begin);   
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-15
      • 1970-01-01
      相关资源
      最近更新 更多