关于c#:将dataGridView行导出到Excel或SQL Server数据库的最快方法是什么

What is the fastest way to export dataGridView rows to Excel or into an SQL Server database

将460328-800328范围内的DataGridView行导出到Excel或SQL Server数据库表时,如果不使用Microsoft Office Interop,则最快的方法是什么?因为Interop速度非常慢,而且对系统资源的占用非常大?


对于导出到Excel,如果不使用基于XML的2007或2010,则interop几乎是唯一的方法。不过,它并没有它的名声那么坏。我将列出一些解决方案。

1到Excel

首先将Microsoft.Office.Interop.Excel组件引用添加到项目中。这应该在"项目"->"添加引用"中的.NET选项卡下。将using语句添加到表单中:

0

添加按钮控件,并将此代码添加到其正文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    private void btnExport_Click(object sender, EventArgs e)
    {

        Excel.Application app = new Excel.Application();
        app.Visible = true;
        Excel.Workbook wb = app.Workbooks.Add(1);
        Excel.Worksheet ws = (Excel.Worksheet)wb.Worksheets[1];
        // changing the name of active sheet
        ws.Name ="Exported from gridview";

        ws.Rows.HorizontalAlignment = HorizontalAlignment.Center;
        // storing header part in Excel
        for (int i = 1; i < dataGridView1.Columns.Count + 1; i++)
        {
            ws.Cells[1, i] = dataGridView1.Columns[i - 1].HeaderText;
        }


        // storing Each row and column value to excel sheet
        for (int i = 0; i < dataGridView1.Rows.Count - 1; i++)
        {
            for (int j = 0; j < dataGridView1.Columns.Count; j++)
            {
                ws.Cells[i + 2, j + 1] = dataGridView1.Rows[i].Cells[j].Value.ToString();
            }
        }

        // sizing the columns
        ws.Cells.EntireColumn.AutoFit();

        // save the application
        wb.SaveAs("c:\\output.xls",Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive , Type.Missing, Type.Missing, Type.Missing, Type.Missing);

        // Exit from the application
       app.Quit();
    }
}

2-到SQL Server

这不需要互操作。为便于使用,请将列表对象传递给执行插入的事件。如果设置了与网格视图列相对应的表,则很容易。在这里,我使用一个存储过程。

2

如果我需要为你调整一下,请告诉我。在最初的示例中,我在表单_Load方法中声明了list rows=new list()。这对该解决方案有效,但其范围现在太有限了。我已经将其向上/向外移动到类中,以便可以在表单的任何位置调用in(特别是btnotsql_click)。我已经在下面发表了评论:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    List<Row> rows = new List<Row>();

    private void Form1_Load(object sender, EventArgs e)
    {
        //var rows = new List<Row>();  //limited scope
        var sr = new StreamReader(@"C:\so_test.txt");
        while (!sr.EndOfStream)
        {
            string s = sr.ReadLine();
            if (!String.IsNullOrEmpty(s.Trim()))
            {
                rows.Add(new Row(s));
            }
        }
        sr.Close();
        dataGridView1.DataSource = rows;
    }


在没有Office的情况下从C中签出创建Excel文件,因为这意味着使用EPPLUS非常有效-我可以从数据表中创建我的csv数据,并在内存中大容量加载要输出的Excel文件。只需几行代码。variable csvdata是所有csvdata的字符串值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    using( ExcelPackage pck = new ExcelPackage( ) )
    {
      //Create the worksheet
      ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Sheet1" );

      // set the delimiter
      etf.Delimiter = ',';
      etf.EOL ="
"
;
      etf.TextQualifier =""";

      //Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
      ws.Cells["
A1"].LoadFromText( csvData, etf );
      return pck.GetAsByteArray( );
   }


对于传输到Excel,这是我找到的最快的方法(尽管它确实使用Office Interop)。循环遍历DataGridView中的每个单元格,并将其分配给对象数组。然后将整个数组赋给Excel区域。这比单独为每个Excel单元格赋值快得多,因为它只调用一次互操作。原谅VB:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Sub Export()
    Dim xlApp As New Excel.Application
    Dim wb As Excel.Workbook = xlApp.Workbooks.Add
    Dim ws As Excel.Worksheet = wb.Worksheets(1)
    Dim dgv as DataGridView = MyDataGridView

    Dim ExportArray(dgv.Rows.Count, dgv.Columns.Count - 1) As Object
    Dim j, i As Integer

    For j = 0 To dgv.Columns.Count - 1
        ExportArray(0, j) = dgv.Columns(j).Name
        For i = 1 To dgv.Rows.Count
            ExportArray(i, j) = dgv(j, i - 1).Value
        Next
    Next

    Dim col As String = ColNumtoLetter(j)
    ws.Range("A1:" & col & i).Value = ExportArray
End Sub

Private Function ColNumtoLetter(ByVal iCol As Integer) As String
    Dim Result As String =""

    Dim iAlpha As Integer = Int(iCol / 26.001)
    Dim iRemainder As Integer = iCol - (iAlpha * 26)

    If iAlpha > 0 Then
        Result = Chr(iAlpha + 64)
    End If
    If iRemainder > 0 Then
        Result = Result & Chr(iRemainder + 64)
    End If

    Return Result
End Function

第二个方法只是将最后一个列号转换为相应的Excel列名。

有关详细信息,请参阅"从数据集快速导出到Excel"和"更快地将数据导出到Excel"。


在这里,我使用DataTable将数据写入Excel文件。我认为数据网格视图也与数据表相同。

首先从数据库获取数据:

1
db.GetData(sqlgetprint);

方法的调用方法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class DataBaseConnection
{
    private OdbcConnection conn1 = new OdbcConnection(@"FILEDSN=C:/OTPub/Ot.dsn;" +"Uid=sa;" +"Pwd=otdata@123;"); //"DSN=Ot_DataODBC;" +"Uid=sa;" + "Pwd=otdata@123;"

    //select
    public System.Data.DataTable GetData(string sql)
    {
        try
        {

            conn1.Open();
            OdbcDataAdapter adpt = new OdbcDataAdapter(sql, conn1);
            DataTable dt = new DataTable();
            adpt.Fill(dt);
            conn1.Close();
            return dt;

        }
        catch (Exception ex)
        {
            conn1.Close();
            throw ex;
        }
    }    
}

之后,在工作窗体中为databaseconcentation类创建对象

1
 DataBaseConnection db = new DataBaseConnection();

在按钮单击事件中,可以将此代码写入Excel文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
string sqlgetprint ="SELECT  Service_No,Full_name, Acc_No, OP_date, On_time, Off_time, OP_hours, Payment  FROM   Print_Op ORDER BY Service_No , OP_date";
            DataTable dtall = db.GetData(sqlgetprint);

            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Filter ="Excel Documents (*.xls)|*.xls";
            saveFileDialog1.FileName ="Employee Details.xls";

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                string fname = saveFileDialog1.FileName;


                StreamWriter wr = new StreamWriter(fname);
                for (int i = 0; i < dtall.Columns.Count; i++)
                {
                    wr.Write(dtall.Columns[i].ToString().ToUpper() +"\t");
                }

                wr.WriteLine();

                //write rows to excel file
                for (int i = 0; i < (dtall.Rows.Count); i++)
                {
                    for (int j = 0; j < dtall.Columns.Count; j++)
                    {
                        if (dtall.Rows[i][j] != null)
                        {
                            wr.Write(Convert.ToString(dtall.Rows[i][j]) +"\t");
                        }
                        else
                        {
                            wr.Write("\t");
                        }
                    }
                    //go to next line
                    wr.WriteLine();
                }
                //close file
                wr.Close();
                if (File.Exists(fname))
                {
                    System.Diagnostics.Process.Start(fname);
                }

            }
        }

        catch (Exception)
        {

            MessageBox.Show("Error Create Excel Sheet!");
        }

一种选择是将数据写入csv文件,而不是Excel文件。Excel在阅读之后不会有问题。

如果您不熟悉,在csv(即逗号分隔)文件中,字段由逗号分隔,行由换行符分隔(

)。

类似(可能无法编译!):

1
2
3
4
5
6
7
8
9
10
11
12
13
private void WriteData() {
    using (var file = System.IO.StreamWriter(@"C:\Path\To\File.csv")) {
        foreach (var row in dataGrid.Rows) {
             foreach (var cell in row.Cells) {
                 // Note that if some cells contain commas,
                 // you'd need to wrap them in quotes.
                 file.Write(cell.Value).Write(",");
             }
        }
        file.Write("
"
);
    }
}

为了提高性能,最好将几百(或数千)行收集到一个字符串中,然后将其写入一个文件,而不是逐个单元地写入。


这可能更快,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    using Excel = Microsoft.Office.Interop.Excel;

    public static void SaveGridToExcel(DataGridView DGV)
    {

        if (DGV.Rows.Count > 0)
        {
            string filename ="";
            SaveFileDialog SV = new SaveFileDialog();
            SV.Filter ="EXCEL FILES|*.xlsx;*.xls";
            DialogResult result = SV.ShowDialog();


            if (result == DialogResult.OK)
            {

                filename = SV.FileName;
                bool multiselect = DGV.MultiSelect;
                DGV.MultiSelect = true;
                DGV.SelectAll();
                DGV.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
                Clipboard.SetDataObject(DGV.GetClipboardContent());
                var results = System.Convert.ToString(Clipboard.GetData(DataFormats.Text));
                DGV.ClearSelection();
                DGV.MultiSelect = multiselect;
                Microsoft.Office.Interop.Excel.Application XCELAPP = null;
                Microsoft.Office.Interop.Excel.Workbook XWORKBOOK = null;
                Microsoft.Office.Interop.Excel.Worksheet XSHEET = null;
                object misValue = System.Reflection.Missing.Value;
                XCELAPP = new Excel.Application();
                XWORKBOOK = XCELAPP.Workbooks.Add(misValue);
                XCELAPP.DisplayAlerts = false;
                XCELAPP.Visible = false;
                XSHEET = XWORKBOOK.ActiveSheet;
                XSHEET.Paste();
                XWORKBOOK.SaveAs(filename, Excel.XlFileFormat.xlOpenXMLWorkbook);
                XWORKBOOK.Close(false);
                XCELAPP.Quit();
                try
                {                      
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(XSHEET);
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(XWORKBOOK);
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(XCELAPP);
                }
                catch { }
            }
        }
    }