การสร้างไฟล์ Excel ใน ASP.NET [ปิด]


99

ฉันกำลังจะเพิ่มส่วนในแอป ASP.NET (VB.NET codebehind) ที่จะช่วยให้ผู้ใช้รับข้อมูลกลับมาเป็นไฟล์ Excel ซึ่งฉันจะสร้างตามข้อมูลฐานข้อมูล แม้ว่าจะมีหลายวิธีในการทำเช่นนี้ แต่แต่ละวิธีก็มีข้อเสียของตัวเอง คุณจะส่งคืนข้อมูลอย่างไร ฉันกำลังมองหาสิ่งที่สะอาดและตรงไปตรงมาที่สุด


คำตอบ:


131

CSV

ข้อดี:

  • เรียบง่าย

จุดด้อย:

  • อาจไม่ทำงานในตำแหน่งที่ตั้งอื่นหรือในการกำหนดค่า Excel ที่แตกต่างกัน (เช่นตัวคั่นรายการ)
  • ไม่สามารถใช้การจัดรูปแบบสูตร ฯลฯ

HTML

ข้อดี:

  • ยังคงค่อนข้างเรียบง่าย
  • รองรับการจัดรูปแบบและสูตรอย่างง่าย

จุดด้อย:

  • คุณต้องตั้งชื่อไฟล์เป็น xls และ Excel อาจเตือนคุณเกี่ยวกับการเปิดไฟล์ Excel ที่ไม่ใช่เนทีฟ
  • หนึ่งแผ่นงานต่อสมุดงาน

OpenXML (Office 2007 .XLSX)

ข้อดี:

  • รูปแบบ Excel ดั้งเดิม
  • รองรับคุณสมบัติ Excel ทั้งหมด
  • ไม่ต้องการสำเนาติดตั้งของ Excel
  • สามารถสร้างตาราง Pivot
  • สามารถสร้างได้โดยใช้โครงการโอเพนซอร์สEPPlus

จุดด้อย:

  • ความเข้ากันได้ที่ จำกัด ภายนอก Excel 2007 (ไม่ควรเป็นปัญหาในปัจจุบัน)
  • ซับซ้อนเว้นแต่คุณจะใช้ส่วนประกอบของบุคคลที่สาม

SpreadSheetML (XML รูปแบบเปิด)

ข้อดี:

  • ง่ายเมื่อเทียบกับรูปแบบ Excel ดั้งเดิม
  • รองรับคุณลักษณะของ Excel ส่วนใหญ่: การจัดรูปแบบสไตล์สูตรหลายแผ่นงานต่อสมุดงาน
  • ไม่จำเป็นต้องติดตั้ง Excel เพื่อใช้งาน
  • ไม่จำเป็นต้องใช้ไลบรารีของบุคคลที่สามเพียงเขียน xml ของคุณ
  • เอกสารสามารถเปิดได้โดย Excel XP / 2003/2007

จุดด้อย:

  • ขาดเอกสารที่ดี
  • ไม่รองรับ Excel เวอร์ชันเก่า (ก่อนปี 2000)
  • เขียนอย่างเดียวเมื่อคุณเปิดและทำการเปลี่ยนแปลงจาก Excel ระบบจะแปลงเป็น Excel ดั้งเดิม

XLS (สร้างโดยส่วนประกอบของบุคคลที่สาม)

ข้อดี:

  • สร้างไฟล์ Excel ดั้งเดิมด้วยการจัดรูปแบบสูตรและอื่น ๆ ทั้งหมด

จุดด้อย:

  • เสียเงิน
  • เพิ่มการอ้างอิง

COM Interop

ข้อดี:

  • ใช้ไลบรารีดั้งเดิมของ Microsoft
  • อ่านการสนับสนุนสำหรับเอกสารพื้นเมือง

จุดด้อย:

  • ช้ามาก
  • ปัญหาการจับคู่การอ้างอิง / เวอร์ชัน
  • ปัญหาการทำงานพร้อมกัน / ความสมบูรณ์ของข้อมูลสำหรับการใช้งานเว็บเมื่ออ่าน
  • ช้ามาก
  • ปัญหาการปรับขนาดสำหรับการใช้งานเว็บ (แตกต่างจากการทำงานพร้อมกัน): จำเป็นต้องสร้างแอป Excel จำนวนมากบนเซิร์ฟเวอร์
  • ต้องใช้ Windows
  • ฉันบอกว่ามันช้าหรือเปล่า?

1
ข้อ จำกัด "เขียนอย่างเดียว" ที่กล่าวถึงสำหรับ SpreadsheetML ไม่ใช่ปัญหาทั้งหมดเนื่องจากคุณสามารถบันทึกไฟล์ excel เป็น SpreadsheetML ได้หากต้องการ
Brian

1
SpreadsheetML อาจทำให้ Excel 2003 ล้มเหลวหากคุณสร้างไฟล์ขนาดใหญ่ด้วย อย่าเพิ่งวางใจ: /
Brian

2
คุณสามารถบันทึกกลับเป็นไฟล์ SpreadsheetML ได้ใน Office 2002 และ 2003 ไม่ต้องบันทึกตามต้องการ SpreadsheetML ไม่สามารถจัดเก็บมาโครแผนภูมิกราฟิกและอัตราต่อรองและจุดจบอื่น ๆ รวมถึงคุณลักษณะใหม่ของ Office 2007 (เช่นรูปแบบเงื่อนไขมากกว่า 3 รูปแบบ) เนื่องจาก XML เป็นแบบ verbose Zipping SpreadsheetML ก่อนส่งจากเซิร์ฟเวอร์ (โดยใช้ SharpZipLib เป็นตัวเลือก) จึงช่วยลดเวลาในการดาวน์โหลดได้ดี - จริง ๆ แล้วควรกล่าวถึงว่า OpenXML ถูกเก็บไว้ในที่เก็บ ZIP @ ไบรอัน: ฉันใช้ SpreadsheetML ที่ซับซ้อนในช่วง 50-100MB เป็นประจำทุกวันโดยไม่มีปัญหาการขัดข้อง
richardtallent

หากมีความเป็นไปได้ที่คุณจะต้องส่งออกข้อมูลจำนวนมากคุณควรส่งออกเป็น CSV นอกเหนือจาก SpreadsheetML แล้วการสร้างโซลูชันที่มีประสิทธิภาพด้วยรูปแบบอื่น ๆ ยังทำได้ยากกว่า HTML สามารถเขียนและอ่านได้อย่างมีประสิทธิภาพ แต่ต้องการข้อกำหนดเพิ่มเติมในส่วนของคุณเพื่อเป็นประโยชน์ ทั้ง HTML และ SpreadsheetML มีปัญหาอื่น ๆ เกี่ยวกับไฟล์ขนาดใหญ่ตามที่ Brian กล่าวถึงในความคิดเห็นของเขา ดังนั้นหากคุณต้องการเพียงแค่การส่งออกข้อมูลอย่างง่ายด้วย CSV
JohannesH

2
@pomarc: อาจจะตรงไปตรงมา แต่ก็ไม่สะอาด ผู้ใช้ต้องการไฟล์ Excel และคุณให้ไฟล์ HTML ที่มีนามสกุลปลอม
Heinzi

38

คุณสามารถส่งออกข้อมูลเป็นเซลล์ตาราง html ติด a .xlsหรือ.xlsxส่วนขยายจากนั้น Excel จะเปิดข้อมูลราวกับว่าเป็นเอกสารดั้งเดิม คุณยังสามารถคำนวณการจัดรูปแบบและสูตรแบบ จำกัด ได้ด้วยวิธีนี้จึงมีประสิทธิภาพมากกว่า CSV นอกจากนี้การส่งออกตาราง html ควรจะทำได้ง่ายมากจากแพลตฟอร์มเว็บเช่น ASP.Net;)

หากคุณต้องการหลายแผ่นหรือชื่อแผ่นงานภายในสมุดงาน Excel ของคุณคุณสามารถทำสิ่งที่คล้ายกันผ่านทางเค้าร่าง XML SpreadSheetMLที่เรียกว่า นี่ไม่ใช่รูปแบบใหม่ที่มาพร้อมกับ Office 2007 แต่เป็นสิ่งที่แตกต่างไปจากเดิมอย่างสิ้นเชิงที่ใช้งานได้นานเท่ากับ Excel 2000 วิธีที่ง่ายที่สุดในการอธิบายวิธีการทำงานคือตัวอย่าง:

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?> 
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
        xmlns:o="urn:schemas-microsoft-com:office:office"
        xmlns:x="urn:schemas-microsoft-com:office:excel"
        xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
        xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
      <Author>Your_name_here</Author>
      <LastAuthor>Your_name_here</LastAuthor>
      <Created>20080625</Created>
      <Company>ABC Inc</Company>
      <Version>10.2625</Version>
</DocumentProperties>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
        <WindowHeight>6135</WindowHeight>
        <WindowWidth>8445</WindowWidth>
        <WindowTopX>240</WindowTopX>
        <WindowTopY>120</WindowTopY>
        <ProtectStructure>False</ProtectStructure>
        <ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>

<Styles>
      <Style ss:ID="Default" ss:Name="Normal">
            <Alignment ss:Vertical="Bottom" />
            <Borders />
            <Font />
            <Interior />
            <NumberFormat />
            <Protection />
      </Style>
</Styles>

<Worksheet ss:Name="Sample Sheet 1">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ID="Table1">
<Column ss:Width="150" />
<Column ss:Width="200" />
<Row>
      <Cell><Data ss:Type="Number">1</Data></Cell>
      <Cell><Data ss:Type="Number">2</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="Number">3</Data></Cell>
      <Cell><Data ss:Type="Number">4</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="Number">5</Data></Cell>
      <Cell><Data ss:Type="Number">6</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="Number">7</Data></Cell>
      <Cell><Data ss:Type="Number">8</Data></Cell>
</Row>
</Table>
</Worksheet>

<Worksheet ss:Name="Sample Sheet 2">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ID="Table2">
<Column ss:Width="150" />
<Column ss:Width="200" />
<Row>
      <Cell><Data ss:Type="String">A</Data></Cell>
      <Cell><Data ss:Type="String">B</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="String">C</Data></Cell>
      <Cell><Data ss:Type="String">D</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="String">E</Data></Cell>
      <Cell><Data ss:Type="String">F</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="String">G</Data></Cell>
      <Cell><Data ss:Type="String">H</Data></Cell>
</Row>
</Table>
</Worksheet>
</Workbook> 

12
คุณสามารถเปลี่ยนชื่อไฟล์ด้วย. xml extensio และเพิ่มสิ่งนี้: <? mso-application progid = "Excel.Sheet"?> หลังจาก <? xml version = "1.0"?> วิธีนี้ Windows จะรับรู้ว่าไฟล์นั้นเป็น ไฟล์ Excel จะให้ไอคอนที่ถูกต้องจะเปิด excel เมื่อคุณคลิกไฟล์และ Excel จะไม่บ่นว่ารูปแบบไฟล์และเนื้อหาไม่ตรงกัน บาย.
pomarc

1
@pomarc ข้อเสียคือโปรแกรมอื่น ๆ ที่นำเข้าไฟล์ excel จะไม่รู้จัก แต่ถึงอย่างนั้นพวกเขาก็คงไม่แยกวิเคราะห์ xml อยู่ดี
Joel Coehoorn

1
ฉันใช้เทคนิคนี้ค่อนข้างประสบความสำเร็จ นี่เป็นคำแนะนำของฉัน - สิ่งสกปรกง่ายและมีประสิทธิภาพมาก
NealB

ปัญหาที่อาจเกิดขึ้นสองประการ (YMMV) กับข้อมูลตาราง HTML ที่มาสก์เป็นไฟล์ XLS: (1) Microsoft Excel จะตัดช่องว่างและศูนย์หน้าโดยอัตโนมัติ และ (2) Microsoft Excel 2010 เตือนผู้ใช้เมื่อเปิดไฟล์ XLS ที่มีข้อมูลตาราง HTML โซลูชันสำหรับ # 1 ดูเหมือนว่าจะเป็น creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (หากช่องว่าง / ศูนย์นำหน้ามีความสำคัญและจำเป็นต้องคงไว้)
iokevins

เพื่อความกระจ่างในขณะที่ฉันพูดถึงตาราง HTML ประเด็นหลักของคำตอบนี้คือ SpreadsheetML ซึ่งเป็นมากกว่าข้อมูลตาราง HTML Excel เห็นว่าเป็นแบบดั้งเดิม
Joel Coehoorn

16

หากมาจากDataTable :

public static void DataTabletoXLS(DataTable DT, string fileName)
{
    HttpContext.Current.Response.Clear();
    HttpContext.Current.Response.Charset = "utf-16";
    HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
    HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.xls", fileName));
    HttpContext.Current.Response.ContentType = "application/ms-excel";

    string tab = "";
    foreach (DataColumn dc in DT.Columns)
    {
        HttpContext.Current.Response.Write(tab + dc.ColumnName.Replace("\n", "").Replace("\t", ""));
        tab = "\t";
    }
    HttpContext.Current.Response.Write("\n");

    int i;
    foreach (DataRow dr in DT.Rows)
    {
        tab = "";
        for (i = 0; i < DT.Columns.Count; i++)
        {
            HttpContext.Current.Response.Write(tab + dr[i].ToString().Replace("\n", "").Replace("\t", ""));
            tab = "\t";
        }
        HttpContext.Current.Response.Write("\n");
    }
    HttpContext.Current.Response.End();
}

จากGridview :

public static void GridviewtoXLS(GridView gv, string fileName)
{
    int DirtyBit = 0;
    int PageSize = 0;
    if (gv.AllowPaging == true)
    {
        DirtyBit = 1;
        PageSize = gv.PageSize;
        gv.AllowPaging = false;
        gv.DataBind();
    }

    HttpContext.Current.Response.Clear();
    HttpContext.Current.Response.Charset = "utf-8";
    HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
    HttpContext.Current.Response.AddHeader(
        "content-disposition", string.Format("attachment; filename={0}.xls", fileName));
    HttpContext.Current.Response.ContentType = "application/ms-excel";

    using (StringWriter sw = new StringWriter())
    using (HtmlTextWriter htw = new HtmlTextWriter(sw))
    {
        //  Create a table to contain the grid
        Table table = new Table();

        //  include the gridline settings
        table.GridLines = gv.GridLines;

        //  add the header row to the table
        if (gv.HeaderRow != null)
        {
            Utilities.Export.PrepareControlForExport(gv.HeaderRow);
            table.Rows.Add(gv.HeaderRow);
        }

        //  add each of the data rows to the table
        foreach (GridViewRow row in gv.Rows)
        {
            Utilities.Export.PrepareControlForExport(row);
            table.Rows.Add(row);
        }

        //  add the footer row to the table
        if (gv.FooterRow != null)
        {
            Utilities.Export.PrepareControlForExport(gv.FooterRow);
            table.Rows.Add(gv.FooterRow);
        }

        //  render the table into the htmlwriter
        table.RenderControl(htw);

        //  render the htmlwriter into the response
        HttpContext.Current.Response.Write(sw.ToString().Replace("£", ""));
        HttpContext.Current.Response.End();
    }

    if (DirtyBit == 1)
    {
        gv.PageSize = PageSize;
        gv.AllowPaging = true;
        gv.DataBind();
    }
}

private static void PrepareControlForExport(Control control)
{
    for (int i = 0; i < control.Controls.Count; i++)
    {
        Control current = control.Controls[i];
        if (current is LinkButton)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as LinkButton).Text));
        }
        else if (current is ImageButton)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as ImageButton).AlternateText));
        }
        else if (current is HyperLink)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as HyperLink).Text));
        }
        else if (current is DropDownList)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as DropDownList).SelectedItem.Text));
        }
        else if (current is CheckBox)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as CheckBox).Checked ? "True" : "False"));
        }

        if (current.HasControls())
        {
            Utilities.Export.PrepareControlForExport(current);
        }
    }
}

1
แค่รหัสที่ฉันต้องการขอบคุณ :)
Kjensen

สก็อตมีเครื่องหมายเงินปอนด์ ("£") คืออะไร จะทำอย่างไรหากต้องการ ตัวละครอื่น ๆ ที่เป็นอันตรายหรือไม่?
Piotr Owsiak

สมบูรณ์แบบ สิ่งที่ฉันต้องการ
Brad Bruce

จริงๆแล้วเครื่องหมาย£เป็นเพียงสิ่งที่ฉันต้องการสำหรับลูกค้าของฉัน คุณสามารถนำมันออกไป
SpoiledTechie.com

ปัญหาที่อาจเกิดขึ้นสองประการ (YMMV) กับข้อมูลตาราง HTML ที่มาสก์เป็นไฟล์ XLS: (1) Microsoft Excel จะตัดช่องว่างและศูนย์หน้าโดยอัตโนมัติ และ (2) Microsoft Excel 2010 เตือนผู้ใช้เมื่อเปิดไฟล์ XLS ที่มีข้อมูลตาราง HTML โซลูชันสำหรับ # 1 ดูเหมือนว่าจะเป็น creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (หากช่องว่าง / ศูนย์นำหน้ามีความสำคัญและจำเป็นต้องคงไว้) ไฟล์ข้อมูล CSV ได้รับผลกระทบอันดับ 1 เมื่อเปิดใน Microsoft Excel
iokevins


5

จากคำตอบที่ได้รับและการปรึกษาหารือกับเพื่อนร่วมงานปรากฏว่าทางออกที่ดีที่สุดคือการสร้างไฟล์ XML หรือตาราง HTML แล้วดันลงมาเป็นไฟล์แนบ การเปลี่ยนแปลงอย่างหนึ่งที่แนะนำโดยเพื่อนร่วมงานของฉันคือข้อมูล (เช่นตาราง HTML) สามารถเขียนลงในวัตถุตอบกลับได้โดยตรงจึงไม่จำเป็นต้องเขียนไฟล์ซึ่งอาจเป็นปัญหาเนื่องจากปัญหาเกี่ยวกับสิทธิ์ I / O การช่วงชิงและสร้างความมั่นใจว่าการกวาดล้างตามกำหนดการจะเกิดขึ้น

นี่คือตัวอย่างของโค้ด ... ฉันยังไม่ได้ตรวจสอบและยังไม่ได้ระบุรหัสที่เรียกทั้งหมด แต่ฉันคิดว่ามันแสดงถึงแนวคิดได้ดี

    Dim uiTable As HtmlTable = GetUiTable(groupedSumData)

    Response.Clear()

    Response.ContentType = "application/vnd.ms-excel"
    Response.AddHeader("Content-Disposition", String.Format("inline; filename=OSSummery{0:ddmmssf}.xls", DateTime.Now))

    Dim writer As New System.IO.StringWriter()
    Dim htmlWriter As New HtmlTextWriter(writer)
    uiTable.RenderControl(htmlWriter)
    Response.Write(writer.ToString)

    Response.End()

2
แดนคุณมาถูกทางแล้ว และฉันขอแนะนำ SpreadsheetML มากกว่า HTML - ห้องหายใจสำหรับอนาคตเนื่องจากการรองรับ HTML มีข้อ จำกัด อย่างน่าผิดหวัง แต่ด้วย HTML, SpreadsheetML และ OpenXML ขนาดไฟล์อาจค่อนข้างใหญ่และเซิร์ฟเวอร์จะไม่ถูกบีบอัด OpenXML ต้องการคอนเทนเนอร์ ZIP ที่มีไฟล์หลายไฟล์อยู่ข้างในและทั้ง SpreadsheetML และ HTML จะดาวน์โหลดได้เร็วกว่ามากหากคุณ zip ก่อนและส่ง zip เป็นไฟล์แนบ ใช้ SharpZipLib และสตรีมไปที่มันแทนการตอบสนองโดยตรง
richardtallent

4

เนื่องจาก Excel เข้าใจ HTML คุณสามารถเขียนข้อมูลออกมาเป็นตาราง HTML ไปยังไฟล์ temp ที่มีนามสกุล. xls รับ FileInfo สำหรับไฟล์และระเบิดกลับโดยใช้

Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + fi.Name);
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(fi.FullName);
Response.End();

หากคุณต้องการหลีกเลี่ยงไฟล์ temp คุณสามารถเขียนลงในสตรีมในหน่วยความจำและเขียนไบต์กลับแทนการใช้ WriteFile

หากไม่ใส่ส่วนหัวความยาวของเนื้อหาคุณสามารถเขียน html กลับได้โดยตรง แต่อาจทำงานไม่ถูกต้องตลอดเวลาในทุกเบราว์เซอร์


2
ปัญหาที่อาจเกิดขึ้นสองประการ (YMMV) กับข้อมูลตาราง HTML ที่มาสก์เป็นไฟล์ XLS: (1) Microsoft Excel จะตัดช่องว่างและศูนย์หน้าโดยอัตโนมัติ และ (2) Microsoft Excel 2010 เตือนผู้ใช้เมื่อเปิดไฟล์ XLS ที่มีข้อมูลตาราง HTML โซลูชันสำหรับ # 1 ดูเหมือนว่าจะเป็น creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (หากช่องว่าง / ศูนย์นำหน้ามีความสำคัญและจำเป็นต้องคงไว้)
iokevins

3

โดยส่วนตัวแล้วฉันชอบวิธี XML มากกว่า ฉันจะส่งคืนข้อมูลจากฐานข้อมูลในชุดข้อมูลบันทึกลงใน XMl จากนั้นฉันสร้างไฟล์ xslt ที่มีกฎการแปลงที่จะจัดรูปแบบเอกสารที่เหมาะสมและการแปลง XML อย่างง่ายจะทำให้งานเสร็จสิ้น ส่วนที่ดีที่สุดคือคุณสามารถจัดรูปแบบเซลล์ทำการจัดรูปแบบตามเงื่อนไขตั้งค่าส่วนหัวและส่วนท้ายและแม้แต่กำหนดช่วงการพิมพ์


2

ฉันได้ทำสองสามครั้งแล้วและทุกครั้งวิธีที่ง่ายที่สุดคือเพียงส่งคืนไฟล์ CSV (Comma Separated Value) Excel นำเข้าอย่างสมบูรณ์แบบและทำได้ค่อนข้างรวดเร็ว


ปัญหาที่อาจเกิดขึ้นอย่างหนึ่ง (YMMV) กับข้อมูล CSV: Microsoft Excel จะตัดช่องว่างนำหน้าและศูนย์โดยอัตโนมัติ
iokevins

2

เราส่งออกข้อมูลจากดาต้ากริดไปยัง excel ตลอดเวลา แปลงเป็น HTML จากนั้นเขียนลงในไฟล์ excel

Response.ContentType = "application/vnd.ms-excel"
    Response.Charset = ""
    Response.AddHeader("content-disposition", "fileattachment;filename=YOURFILENAME.xls")
    Me.EnableViewState = False
    Dim sw As System.IO.StringWriter = New System.IO.StringWriter
    Dim hw As HtmlTextWriter = New HtmlTextWriter(sw)
    ClearControls(grid)
    grid.RenderControl(hw)
    Response.Write(sw.ToString())
    Response.End()

gotcha เดียวที่ใช้วิธีนี้คือกริดจำนวนมากของเรามีปุ่มหรือลิงก์อยู่ดังนั้นคุณต้องใช้สิ่งนี้ด้วย:

'needed to export grid to excel to remove link button control and represent as text
Private Sub ClearControls(ByVal control As Control)
    Dim i As Integer
    For i = control.Controls.Count - 1 To 0 Step -1
        ClearControls(control.Controls(i))
    Next i

    If TypeOf control Is System.Web.UI.WebControls.Image Then
        control.Parent.Controls.Remove(control)
    End If

    If (Not TypeOf control Is TableCell) Then
        If Not (control.GetType().GetProperty("SelectedItem") Is Nothing) Then
            Dim literal As New LiteralControl
            control.Parent.Controls.Add(literal)
            Try
                literal.Text = CStr(control.GetType().GetProperty("SelectedItem").GetValue(control, Nothing))
            Catch
            End Try
            control.Parent.Controls.Remove(control)
        Else
            If Not (control.GetType().GetProperty("Text") Is Nothing) Then
                Dim literal As New LiteralControl
                control.Parent.Controls.Add(literal)
                literal.Text = CStr(control.GetType().GetProperty("Text").GetValue(control, Nothing))
                control.Parent.Controls.Remove(control)
            End If
        End If
    End If
    Return
End Sub

ฉันพบว่าบางแห่งมันใช้งานได้ดี


2
ปัญหาที่อาจเกิดขึ้นสองประการ (YMMV) กับข้อมูลตาราง HTML ที่มาสก์เป็นไฟล์ XLS: (1) Microsoft Excel จะตัดช่องว่างและศูนย์หน้าโดยอัตโนมัติ และ (2) Microsoft Excel 2010 เตือนผู้ใช้เมื่อเปิดไฟล์ XLS ที่มีข้อมูลตาราง HTML โซลูชันสำหรับ # 1 ดูเหมือนว่าจะเป็น creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (หากช่องว่าง / ศูนย์นำหน้ามีความสำคัญและจำเป็นต้องคงไว้)
iokevins


2

นี่คือรายงานที่ดึงมาจากขั้นตอนการจัดเก็บ ผลลัพธ์จะถูกส่งออกไปยัง Excel ใช้ ADO แทน ADO.NET และเหตุผลว่าทำไมถึงเป็นบรรทัดนี้

oSheet.Cells(2, 1).copyfromrecordset(rst1)

ใช้งานได้เกือบทั้งหมดและไม่มีให้ใช้งานในเว็บไซต์

‘Calls stored proc in SQL Server 2000 and puts data in Excel and ‘formats it

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim cnn As ADODB.Connection
        cnn = New ADODB.Connection
        cnn.Open("Provider=SQLOLEDB;data source=xxxxxxx;" & _
          "database=xxxxxxxx;Trusted_Connection=yes;")

        Dim cmd As New ADODB.Command


        cmd.ActiveConnection = cnn


        cmd.CommandText = "[sp_TomTepley]"
        cmd.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
        cmd.CommandTimeout = 0
        cmd.Parameters.Refresh()


        Dim rst1 As ADODB.Recordset
        rst1 = New ADODB.Recordset
        rst1.Open(cmd)

        Dim oXL As New Excel.Application
        Dim oWB As Excel.Workbook
        Dim oSheet As Excel.Worksheet

        'oXL = CreateObject("excel.application")
        oXL.Visible = True
        oWB = oXL.Workbooks.Add
        oSheet = oWB.ActiveSheet

        Dim Column As Integer
        Column = 1

        Dim fld As ADODB.Field
        For Each fld In rst1.Fields

            oXL.Workbooks(1).Worksheets(1).Cells(1, Column).Value = fld.Name
            oXL.Workbooks(1).Worksheets(1).cells(1, Column).Interior.ColorIndex = 15
            Column = Column + 1

        Next fld

        oXL.Workbooks(1).Worksheets(1).name = "Tom Tepley Report"
        oSheet.Cells(2, 1).copyfromrecordset(rst1)
        oXL.Workbooks(1).Worksheets(1).Cells.EntireColumn.AutoFit()


        oXL.Visible = True
        oXL.UserControl = True

        rst1 = Nothing

        cnn.Close()
        Beep()

    End Sub

1

หากคุณกรอกข้อมูลใน GridView คุณสามารถใช้ฟังก์ชันนี้เพื่อรับข้อมูลที่จัดรูปแบบ HTML ได้ แต่ระบุว่าเบราว์เซอร์เป็นไฟล์ excel

 Public Sub ExportToExcel(ByVal fileName As String, ByVal gv As GridView)

        HttpContext.Current.Response.Clear()
        HttpContext.Current.Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", fileName))
        HttpContext.Current.Response.ContentType = "application/ms-excel"

        Dim sw As StringWriter = New StringWriter
        Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
        Dim table As Table = New Table

        table.GridLines = gv.GridLines

        If (Not (gv.HeaderRow) Is Nothing) Then
            PrepareControlForExport(gv.HeaderRow)
            table.Rows.Add(gv.HeaderRow)
        End If

        For Each row As GridViewRow In gv.Rows
            PrepareControlForExport(row)
            table.Rows.Add(row)
        Next

        If (Not (gv.FooterRow) Is Nothing) Then
            PrepareControlForExport(gv.FooterRow)
            table.Rows.Add(gv.FooterRow)
        End If

        table.RenderControl(htw)

        HttpContext.Current.Response.Write(sw.ToString)
        HttpContext.Current.Response.End()

    End Sub


    Private Sub PrepareControlForExport(ByVal control As Control)

        Dim i As Integer = 0

        Do While (i < control.Controls.Count)

            Dim current As Control = control.Controls(i)

            If (TypeOf current Is LinkButton) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, LinkButton).Text))

            ElseIf (TypeOf current Is ImageButton) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, ImageButton).AlternateText))

            ElseIf (TypeOf current Is HyperLink) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, HyperLink).Text))

            ElseIf (TypeOf current Is DropDownList) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, DropDownList).SelectedItem.Text))

            ElseIf (TypeOf current Is CheckBox) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, CheckBox).Checked))

            End If

            If current.HasControls Then
                PrepareControlForExport(current)
            End If

            i = i + 1

        Loop

    End Sub

ปัญหาที่อาจเกิดขึ้นสองประการ (YMMV) กับข้อมูลตาราง HTML ที่มาสก์เป็นไฟล์ XLS: (1) Microsoft Excel จะตัดช่องว่างและศูนย์หน้าโดยอัตโนมัติ และ (2) Microsoft Excel 2010 เตือนผู้ใช้เมื่อเปิดไฟล์ XLS ที่มีข้อมูลตาราง HTML โซลูชันสำหรับ # 1 ดูเหมือนว่าจะเป็น creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (หากช่องว่าง / ศูนย์นำหน้ามีความสำคัญและจำเป็นต้องคงไว้)
iokevins

1

เพียงหลีกเลี่ยง COM Interop ผ่าน Microsoft.Office.Interop namespace มันช้ามากและไม่น่าเชื่อถือและไม่สามารถปรับขนาดได้ ไม่สามารถใช้ได้กับนักมาโซคิสต์


1

คุณสามารถสร้างการจัดรูปแบบไฟล์ Excel อย่างการใช้ห้องสมุดนี้ค่อนข้างง่าย: http://officehelper.codeplex.com/documentation

Microsoft Office ไม่จำเป็นต้องติดตั้งบนเว็บเซิร์ฟเวอร์!


0

CSV เป็นวิธีที่ง่ายที่สุด เวลาส่วนใหญ่จะเชื่อมโยงกับ Excel มิฉะนั้นคุณต้องใช้ API อัตโนมัติหรือรูปแบบ XML API และ XML ไม่ใช่เรื่องยากที่จะใช้

ข้อมูลเกี่ยวกับการสร้าง XML สำหรับ Excel


0

ฉันไปตามเส้นทาง CSV (ตามที่อธิบายไว้ข้างต้น) หรือบ่อยกว่านั้นในทุกวันนี้ฉันใช้ Infragistics NetAdvantage เพื่อสร้างไฟล์ (ส่วนใหญ่ในช่วงเวลาที่ Infragistics เล่นอยู่เราแค่ส่งออก UltraWebGrid ที่มีอยู่ซึ่งโดยพื้นฐานแล้วเป็นโซลูชันเดียวใน LOC เว้นแต่จะต้องมีการปรับแต่งการจัดรูปแบบเพิ่มเติมเราสามารถสร้างไฟล์ Excel / BIFF ด้วยตนเองได้เช่นกัน แต่แทบไม่จำเป็นต้องทำ)


0

ผู้ชายใน. net ฉันเดาว่าคุณอาจมีส่วนประกอบที่สามารถทำเช่นนั้นได้ แต่ใน asp คลาสสิกฉันได้สร้างตาราง html แล้วและเปลี่ยน mime tipe ของหน้าเป็น vnd / msexcel ฉันเดาว่าถ้าคุณใช้ gridview และเปลี่ยนประเภท mime มันน่าจะใช้ได้เพราะ gridview เป็นตาราง html


ปัญหาที่อาจเกิดขึ้นสองประการ (YMMV) กับข้อมูลตาราง HTML ที่มาสก์เป็นไฟล์ XLS: (1) Microsoft Excel จะตัดช่องว่างและศูนย์หน้าโดยอัตโนมัติ และ (2) Microsoft Excel 2010 เตือนผู้ใช้เมื่อเปิดไฟล์ XLS ที่มีข้อมูลตาราง HTML โซลูชันสำหรับ # 1 ดูเหมือนว่าจะเป็น creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (หากช่องว่าง / ศูนย์นำหน้ามีความสำคัญและจำเป็นต้องคงไว้)
iokevins

0

วิธีเดียวในการหลีกเลี่ยงสัญลักษณ์สีเขียว "ดูเหมือนว่าตัวเลขเหล่านี้จะถูกเก็บเป็นข้อความ" คือการใช้รูปแบบ Open XML มันคุ้มค่าที่จะใช้มันเพียงเพื่อหลีกเลี่ยงสามเหลี่ยมสีเขียวที่หลีกเลี่ยงไม่ได้


0

วิธีที่ดีที่สุดที่ฉันเคยเห็นสำหรับรายงาน excel คือการเขียนข้อมูลใน XML ด้วยส่วนขยาย XML และสตรีมไปยังไคลเอนต์ด้วยประเภทเนื้อหาที่ถูกต้อง (แอปพลิเคชัน / xls)

ใช้งานได้กับรายงานใด ๆ ที่ต้องใช้การจัดรูปแบบพื้นฐานและช่วยให้คุณเปรียบเทียบกับสเปรดชีตที่มีอยู่ได้โดยใช้เครื่องมือเปรียบเทียบข้อความ


0

สมมติว่านี้เป็นอินทราเน็ตที่คุณสามารถกำหนดสิทธิ์และอาณัติ IE คุณสามารถสร้างสมุดงานด้านลูกค้าที่มีJScript / VBScript ขับรถ Excel สิ่งนี้ช่วยให้คุณสามารถจัดรูปแบบ Excel ได้โดยไม่ต้องวุ่นวายกับการพยายามทำให้ Excel เป็นอัตโนมัติบนเซิร์ฟเวอร์

ฉันไม่แน่ใจว่าฉันจะแนะนำแนวทางนี้อีกต่อไปจริงๆยกเว้นในสถานการณ์เฉพาะ แต่มันเป็นเรื่องธรรมดาในช่วงเฮโรอีน ASP แบบคลาสสิก


0

แน่นอนคุณสามารถเลือกใช้ส่วนประกอบของบุคคลที่สามได้ตลอดเวลา โดยส่วนตัวแล้วฉันมีประสบการณ์ที่ดีกับ Spire.XLS http://www.e-iceblue.com/xls/xlsintro.htm

ส่วนประกอบค่อนข้างใช้งานง่ายภายในแอปพลิเคชันของคุณ:

        Workbook workbook = new Workbook();

        //Load workbook from disk.
        workbook.LoadFromFile(@"Data\EditSheetSample.xls");
        //Initailize worksheet
        Worksheet sheet = workbook.Worksheets[0];

        //Writes string
        sheet.Range["B1"].Text = "Hello,World!";
        //Writes number
        sheet.Range["B2"].NumberValue = 1234.5678;
        //Writes date
        sheet.Range["B3"].DateTimeValue = System.DateTime.Now;
        //Writes formula
        sheet.Range["B4"].Formula = "=1111*11111";

        workbook.SaveToFile("Sample.xls");

0

ปัญหาอย่างหนึ่งที่ฉันพบโดยใช้หนึ่งในวิธีแก้ปัญหาที่แนะนำข้างต้นซึ่งคล้ายกับคำตอบนี้คือถ้าคุณดันเนื้อหาออกเป็นไฟล์แนบ (สิ่งที่ฉันพบว่าเป็นวิธีแก้ปัญหาที่สะอาดที่สุดสำหรับเบราว์เซอร์ที่ไม่ใช่ ms) จากนั้นเปิดใน Excel 2000-2003 ประเภทคือ "Excel Web Page" ไม่ใช่เอกสาร Excel ดั้งเดิม

จากนั้นคุณต้องอธิบายให้ผู้ใช้ทราบถึงวิธีการใช้ "บันทึกเป็นประเภท" จากใน Excel เพื่อแปลงเป็นเอกสาร Excel นี่เป็นความเจ็บปวดหากผู้ใช้จำเป็นต้องแก้ไขเอกสารนี้แล้วอัปโหลดไปที่ไซต์ของคุณอีกครั้ง

คำแนะนำของฉันคือใช้ CSV เป็นเรื่องง่ายและหากผู้ใช้เปิดจากภายใน Excel อย่างน้อย Excel ก็จะแจ้งให้พวกเขาบันทึกในรูปแบบดั้งเดิม


คุณจะต้องระมัดระวัง CSV หากผู้ใช้ของคุณกระจัดกระจายไปทั่วโลก ที่นี่ในเยอรมนีจะใช้จุลภาคเป็นตัวคั่นทศนิยมดังนั้นจึงใช้อัฒภาคเป็นตัวคั่นค่า ทำให้ยากในการสร้างไฟล์เดียวซึ่งสามารถอ่านได้ในทุกวัฒนธรรมที่แตกต่างกัน ดังนั้นการโหวตของฉันจะเป็นหนึ่งในรูปแบบ XML
พอล

0

ฉันจะสร้างไฟล์ CSV ตามข้อมูลเพราะฉันเห็นว่าเป็นไฟล์ที่สะอาดที่สุดและ Excel มีการสนับสนุนที่ดี แต่ถ้าคุณต้องการรูปแบบที่ยืดหยุ่นกว่านี้ฉันแน่ใจว่ามีเครื่องมือของบุคคลที่สามสำหรับสร้างไฟล์ excel จริง


0

นี่คือวิธีแก้ปัญหาสตรีมข้อมูลออกเป็น CSV รวดเร็วสะอาดและใช้งานง่ายและจัดการกับเครื่องหมายจุลภาคในอินพุต

public static void ExportToExcel(DataTable data, HttpResponse response, string fileName)
{
    response.Charset = "utf-8";
    response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
    response.Cache.SetCacheability(HttpCacheability.NoCache);
    response.ContentType = "text/csv";
    response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);

    for (int i = 0; i < data.Columns.Count; i++)
    {
       response.Write(data.Columns[i].ColumnName);
       response.Write(i == data.Columns.Count - 1 ? "\n" : ",");
    }        
    foreach (DataRow row in data.Rows)
    {
        for (int i = 0; i < data.Columns.Count; i++)
        {
            response.Write(String.Format("\"{0}\"", row[i].ToString()));
            response.Write(i == data.Columns.Count - 1 ? "\n" : ",");
        }
    }

    response.End();
}

-1

เพิ่งสร้างฟังก์ชันเพื่อส่งออกจากเว็บฟอร์ม C # เพื่อ excel หวังว่าจะช่วยให้ผู้อื่น

    public void ExportFileFromSPData(string filename, DataTable dt)
    {
        HttpResponse response = HttpContext.Current.Response;

        //clean up the response.object
        response.Clear();
        response.Buffer = true;
        response.Charset = "";

        // set the response mime type for html so you can see what are you printing 
        //response.ContentType = "text/html";
        //response.AddHeader("Content-Disposition", "attachment;filename=test.html");

        // set the response mime type for excel
        response.ContentType = "application/vnd.ms-excel";
        response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
        response.ContentEncoding = System.Text.Encoding.UTF8;
        response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble());

        //style to format numbers to string
        string style = @"<style> .text { mso-number-format:\@; } </style>";
        response.Write(style);

        // create a string writer
        using (StringWriter sw = new StringWriter())
        {
            using (HtmlTextWriter htw = new HtmlTextWriter(sw))
            {
                // instantiate a datagrid
                GridView dg = new GridView();
                dg.DataSource = dt;
                dg.DataBind();

                foreach (GridViewRow datarow in dg.Rows)
                {
                    //format specific cell to be text 
                    //to avoid 1.232323+E29 to get 1232312312312312124124
                    datarow.Cells[0].Attributes.Add("class", "text");
                }

                dg.RenderControl(htw);
                response.Write(sw.ToString());
                response.End();
            }
        }
     }

-5

หากคุณต้องใช้ Excel แทนไฟล์ CSV คุณจะต้องใช้ OLE อัตโนมัติในอินสแตนซ์ Excel ที่เซิร์ฟเวอร์ วิธีที่ง่ายที่สุดคือการมีไฟล์เทมเพลตและกรอกข้อมูลด้วยโปรแกรม คุณบันทึกลงในไฟล์อื่น

เคล็ดลับ:

  • อย่าทำแบบโต้ตอบ ให้ผู้ใช้เริ่มต้นกระบวนการจากนั้นโพสต์หน้าที่มีลิงก์ไปยังไฟล์ วิธีนี้ช่วยลดปัญหาด้านประสิทธิภาพที่อาจเกิดขึ้นในขณะที่สร้างสเปรดชีต
  • ใช้เทมเพลตตามที่ฉันอธิบายไว้ก่อนหน้านี้ ช่วยให้แก้ไขได้ง่ายขึ้น
  • ตรวจสอบให้แน่ใจว่า Excel ถูกตั้งค่าไม่ให้กล่องโต้ตอบป๊อปอัป บนเว็บเซิร์ฟเวอร์สิ่งนี้จะแขวนอินสแตนซ์ excel ทั้งหมด
  • เก็บอินสแตนซ์ Excel ไว้บนเซิร์ฟเวอร์แยกต่างหากควรอยู่หลังไฟร์วอลล์เพื่อไม่ให้เกิดช่องโหว่ด้านความปลอดภัย
  • จับตาดูการใช้ทรัพยากร การสร้าง Spreadhseet บนอินเทอร์เฟซ OLE อัตโนมัติ (PIA เป็นเพียงแค่ shims เหนือสิ่งนี้) เป็นกระบวนการที่ค่อนข้างหนัก หากคุณต้องการปรับขนาดให้มีปริมาณข้อมูลสูงคุณอาจต้องฉลาดกับสถาปัตยกรรมของคุณ

วิธีการ 'ใช้ mime-types เพื่อหลอกให้ excel เปิดตาราง HTML' จะใช้งานได้หากคุณไม่ทราบว่ารูปแบบของไฟล์นั้นเป็นพื้นฐานเล็กน้อย วิธีการเหล่านี้ยังทำให้ CPU ทำงานหนักบนไคลเอนต์อีกด้วย หากคุณต้องการควบคุมรูปแบบของสเปรดชีตแบบละเอียดคุณอาจต้องใช้ Excel เองเพื่อสร้างไฟล์ตามที่อธิบายไว้ข้างต้น


ความคิดที่ไม่ดีในการทำระบบอัตโนมัติจากเว็บเซิร์ฟเวอร์ ทางเลือกอื่นอาจดูเหมือนแฮ็ก แต่จริงๆแล้วจะทำงานได้ดีขึ้นมาก
Joel Coehoorn

เราใช้ OLE ฝั่งเซิร์ฟเวอร์กับ Excel และปวดหลังมาก หากไม่ใช่เพราะความเสี่ยงต่อผลิตภัณฑ์ของเรา ** เราจะดำเนินการแก้ไขปัญหาอื่น ** ดีกว่าปีศาจที่คุณรู้จัก ...
DaveE
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.