DataTable을 Excel로 내보내는 방법
할 수 요?DataTable
C# 엑셀?윈도 폼DataTable
에 관련지어져 있습니다.DataGridView
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★DataTable
탁월하다.
DataTable을 읽기 쉬운 코드를 사용하여 Excel 워크시트로 만들 수 있습니다.
XLWorkbook wb = new XLWorkbook();
DataTable dt = GetDataTableOrWhatever();
wb.Worksheets.Add(dt,"WorksheetName");
개발자는 반응성이 뛰어나고 도움이 됩니다.이 프로젝트는 활발히 개발되고 있으며 문서화는 훌륭합니다.
간단한 코드를 사용하여 DataTable을 csv로 Excel 파일로 변환합니다.
var lines = new List<string>();
string[] columnNames = dataTable.Columns
.Cast<DataColumn>()
.Select(column => column.ColumnName)
.ToArray();
var header = string.Join(",", columnNames.Select(name => $"\"{name}\""));
lines.Add(header);
var valueLines = dataTable.AsEnumerable()
.Select(row => string.Join(",", row.ItemArray.Select(val => $"\"{val}\"")));
lines.AddRange(valueLines);
File.WriteAllLines("excel.csv", lines);
새로운 됩니다.excel.csv
일반적으로 .exe가 있는 곳 또는 실행원이 되는 현재의 작업 디렉토리로 이동합니다.
고급 옵션은 .net 프레임워크의 DataTable 클래스에 확장 메서드(아래 참조)를 작성하는 것입니다.
이 확장 방식은 다음과 같이 호출할 수 있습니다.
using System;
using System.Collections.Generic;
using System.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using System.Data;
using System.Data.OleDb;
DataTable dt;
// fill table data in dt here
...
// export DataTable to excel
// save excel file without ever making it visible if filepath is given
// don't save excel file, just make it visible if no filepath is given
dt.ExportToExcel(ExcelFilePath);
DataTable 클래스의 확장 메서드:
public static class My_DataTable_Extensions
{
// Export DataTable into an excel file with field names in the header line
// - Save excel file without ever making it visible if filepath is given
// - Don't save excel file, just make it visible if no filepath is given
public static void ExportToExcel(this DataTable tbl, string excelFilePath = null) {
try {
if (tbl == null || tbl.Columns.Count == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
// load excel, and create a new workbook
var excelApp = new Excel.Application();
excelApp.Workbooks.Add();
// single worksheet
Excel._Worksheet workSheet = excelApp.ActiveSheet;
// column headings
for (var i = 0; i < tbl.Columns.Count; i++) {
workSheet.Cells[1, i + 1] = tbl.Columns[i].ColumnName;
}
// rows
for (var i = 0; i < tbl.Rows.Count; i++) {
// to do: format datetime values before printing
for (var j = 0; j < tbl.Columns.Count; j++) {
workSheet.Cells[i + 2, j + 1] = tbl.Rows[i][j];
}
}
// check file path
if (!string.IsNullOrEmpty(excelFilePath)) {
try {
workSheet.SaveAs(excelFilePath);
excelApp.Quit();
MessageBox.Show("Excel file saved!");
}
catch (Exception ex) {
throw new Exception("ExportToExcel: Excel file could not be saved! Check filepath.\n"
+ ex.Message);
}
} else { // no file path is given
excelApp.Visible = true;
}
}
catch (Exception ex) {
throw new Exception("ExportToExcel: \n" + ex.Message);
}
}
}
tuncalik(아이디어에 대해 감사함) 기사를 기반으로 한 솔루션. 그러나 큰 테이블의 경우 훨씬 더 빠르게 동작합니다(또한 명확성이 떨어집니다).
public static class My_DataTable_Extensions
{
/// <summary>
/// Export DataTable to Excel file
/// </summary>
/// <param name="DataTable">Source DataTable</param>
/// <param name="ExcelFilePath">Path to result file name</param>
public static void ExportToExcel(this System.Data.DataTable DataTable, string ExcelFilePath = null)
{
try
{
int ColumnsCount;
if (DataTable == null || (ColumnsCount = DataTable.Columns.Count) == 0)
throw new Exception("ExportToExcel: Null or empty input table!\n");
// load excel, and create a new workbook
Microsoft.Office.Interop.Excel.Application Excel = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbooks.Add();
// single worksheet
Microsoft.Office.Interop.Excel._Worksheet Worksheet = Excel.ActiveSheet;
object[] Header = new object[ColumnsCount];
// column headings
for (int i = 0; i < ColumnsCount; i++)
Header[i] = DataTable.Columns[i].ColumnName;
Microsoft.Office.Interop.Excel.Range HeaderRange = Worksheet.get_Range((Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[1, 1]), (Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[1, ColumnsCount]));
HeaderRange.Value = Header;
HeaderRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGray);
HeaderRange.Font.Bold = true;
// DataCells
int RowsCount = DataTable.Rows.Count;
object[,] Cells = new object[RowsCount, ColumnsCount];
for (int j = 0; j < RowsCount; j++)
for (int i = 0; i < ColumnsCount; i++)
Cells[j, i] = DataTable.Rows[j][i];
Worksheet.get_Range((Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[2, 1]), (Microsoft.Office.Interop.Excel.Range)(Worksheet.Cells[RowsCount + 1, ColumnsCount])).Value = Cells;
// check fielpath
if (ExcelFilePath != null && ExcelFilePath != "")
{
try
{
Worksheet.SaveAs(ExcelFilePath);
Excel.Quit();
System.Windows.MessageBox.Show("Excel file saved!");
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: Excel file could not be saved! Check filepath.\n"
+ ex.Message);
}
}
else // no filepath is given
{
Excel.Visible = true;
}
}
catch (Exception ex)
{
throw new Exception("ExportToExcel: \n" + ex.Message);
}
}
}
이 함수는 내보낼 데이터 테이블과 파일 경로를 전달합니다.
public void CreateCSVFile(ref DataTable dt, string strFilePath)
{
try
{
// Create the CSV file to which grid data will be exported.
StreamWriter sw = new StreamWriter(strFilePath, false);
// First we will write the headers.
//DataTable dt = m_dsProducts.Tables[0];
int iColCount = dt.Columns.Count;
for (int i = 0; i < iColCount; i++)
{
sw.Write(dt.Columns[i]);
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
// Now write all the rows.
foreach (DataRow dr in dt.Rows)
{
for (int i = 0; i < iColCount; i++)
{
if (!Convert.IsDBNull(dr[i]))
{
sw.Write(dr[i].ToString());
}
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
}
sw.Close();
}
catch (Exception ex)
{
throw ex;
}
}
「」를 사용합니다.DocumentFormat.OpenXml
입니다.nuget 키지tontonton 、 singleton from from from from to to to to to to to to to to to to to to to to .「수출」DataTable
★★★★★★★★★★★★★★★★★」DataSet
테이블은 워크북에 개별 시트로 표시됩니다.
메인 클래스
public sealed class OfficeOpenXML
{
private static Lazy<OfficeOpenXML> _instance = new Lazy<OfficeOpenXML>(() => new OfficeOpenXML());
private OfficeOpenXML()
{
}
public static OfficeOpenXML GetInstance()
{
return _instance.Value;
}
public MemoryStream GetExcelStream(DataSet ds, bool firstRowAsHeader = false)
{
if (ds == null || ds.Tables.Count == 0)
{
return null;
}
MemoryStream stream = new MemoryStream();
using (var excel = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook))
{
//create doc and workbook
WorkbookPart workbookPart = excel.AddWorkbookPart();
Workbook workbook = new Workbook();
Sheets sheets = new Sheets();
//loop all tables in the dataset
for (int iTable = 0; iTable < ds.Tables.Count; iTable++)
{
var table = ds.Tables[iTable];
//create sheet part
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
Worksheet worksheet = new Worksheet();
SheetData data = new SheetData();
List<Row> allRows = new List<Row>();
//setting header of the sheet
Row headerRow = new Row() { RowIndex = 1 };
for (int iColumn = 0; iColumn < table.Columns.Count; iColumn++)
{
var col = table.Columns[iColumn];
//if first row of table is not the header then set columns of table as header of sheet
if (!firstRowAsHeader)
{
headerRow.Append(new Cell
{
DataType = CellValues.String,
CellValue = new CellValue(col.ColumnName)
});
}
else
{
headerRow.Append(new Cell
{
DataType = CellValues.String,
CellValue = new CellValue(Convert.ToString(table.Rows[0][col]))
});
}
}
allRows.Add(headerRow);
//setting other data rows
if (table.Rows != null && table.Rows.Count != 0)
{
for (int iRow = firstRowAsHeader ? 1 : 0; iRow < table.Rows.Count; iRow++)
{
var row = table.Rows[iRow];
Row valueRow = new Row { RowIndex = (uint)(iRow + (firstRowAsHeader ? 1 : 2)) };
for (int iColumn = 0; iColumn < table.Columns.Count; iColumn++)
{
var col = table.Columns[iColumn];
valueRow.Append(new Cell
{
DataType = Format(col.DataType),
CellValue = new CellValue(Convert.ToString(row[col]))
});
}
allRows.Add(valueRow);
}
}
//add rows to the data
data.Append(allRows);
worksheet.Append(data);
worksheetPart.Worksheet = worksheet;
worksheetPart.Worksheet.Save();
//add worksheet to main sheets
sheets.Append(new Sheet
{
Name = string.IsNullOrWhiteSpace(table.TableName) ? "Sheet" + (iTable + 1) : table.TableName,
Id = workbookPart.GetIdOfPart(worksheetPart),
SheetId = (uint)iTable + 1
});
}//single table processing ends here
//add created sheets to workbook
workbook.Append(sheets);
excel.WorkbookPart.Workbook = workbook;
excel.WorkbookPart.Workbook.Save();
excel.Close();
}
stream.Seek(0, SeekOrigin.Begin);
stream.Capacity = (int)stream.Length;
return stream;
}
public MemoryStream GetExcelStream(DataTable dt, bool firstRowAsHeader = false)
{
DataSet ds = new DataSet();
ds.Tables.Add(dt);
return GetExcelStream(ds, firstRowAsHeader);
}
#region Excel Helpers
CellValues Format(Type t)
{
switch (t.ToString())
{
case "System.String":
return CellValues.String;
case "System.DateTime":
return CellValues.Date;
case "System.Boolean":
return CellValues.Boolean;
case "System.Int16":
return CellValues.Number;
case "System.Int32":
return CellValues.Number;
case "System.Int64":
return CellValues.Number;
case "System.UInt16":
return CellValues.Number;
case "System.UInt32":
return CellValues.Number;
case "System.UInt64":
return CellValues.Number;
case "System.Decimal":
return CellValues.Number;
case "System.Double":
return CellValues.Number;
case "System.Single":
return CellValues.Number;
default:
return CellValues.String;
}
}
#endregion
}
파일에 저장
var excelApp = OfficeOpenXML.GetInstance();
var dt = GetDataTableFromDB();
using (var stream = excelApp.GetExcelStream(dt, false))//use true to hide datatable columns from excel
{
using (FileStream fs = new FileStream(@"C:\Users\Public\myexcel.xlsx", FileMode.Create))
{
stream.CopyTo(fs);
fs.Flush();
}
}
MVC 응용 프로그램에서 다운로드
public ActionResult DownloadReport()
{
var ds = GetDataSetFromDB();
var excelApp = OfficeOpenXML.GetInstance();
var file = excelApp.GetExcelStream(ds, false);
return File(file, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Guid.NewGuid().ToString() + ".xlsx");
}
가장 쉽고 최선의 방법
private void exportToExcel(DataTable dt)
{
/*Set up work book, work sheets, and excel application*/
Microsoft.Office.Interop.Excel.Application oexcel = new Microsoft.Office.Interop.Excel.Application();
try
{
string path = AppDomain.CurrentDomain.BaseDirectory;
object misValue = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Excel.Workbook obook = oexcel.Workbooks.Add(misValue);
Microsoft.Office.Interop.Excel.Worksheet osheet = new Microsoft.Office.Interop.Excel.Worksheet();
// obook.Worksheets.Add(misValue);
osheet = (Microsoft.Office.Interop.Excel.Worksheet)obook.Sheets["Sheet1"];
int colIndex = 0;
int rowIndex = 1;
foreach (DataColumn dc in dt.Columns)
{
colIndex++;
osheet.Cells[1, colIndex] = dc.ColumnName;
}
foreach (DataRow dr in dt.Rows)
{
rowIndex++;
colIndex = 0;
foreach (DataColumn dc in dt.Columns)
{
colIndex++;
osheet.Cells[rowIndex, colIndex] = dr[dc.ColumnName];
}
}
osheet.Columns.AutoFit();
string filepath = "C:\\Temp\\Book1";
//Release and terminate excel
obook.SaveAs(filepath);
obook.Close();
oexcel.Quit();
releaseObject(osheet);
releaseObject(obook);
releaseObject(oexcel);
GC.Collect();
}
catch (Exception ex)
{
oexcel.Quit();
log.AddToErrorLog(ex, this.Name);
}
}
내 SwiftExcel 라이브러리를 사용할 수 있습니다.데이터를 파일에 직접 쓰기 때문에 성능 및 메모리 사용량이 적을 때 특히 유용합니다.
using (var ew = new ExcelWriter("C:\\temp\\test.xlsx"))
{
for (var row = 1; row <= 100; row++)
{
for (var col = 1; col <= 10; col++)
{
ew.Write($"row:{row}-col:{col}", col, row);
}
}
}
설치할 Nuget 명령어:
Install-Package SwiftExcel
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
ClosedXML.Excel
빠르기도 그것은 쉽고 꽤 빠르다.
https://github.com/ClosedXML/ClosedXML
학급
private DataTable getAllList()
{
string constr = ConfigurationManager.ConnectionStrings["RConnection"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand("SELECT EmpId, gender, EmpName, pOnHold FROM Employee WHERE EmpId= '"+ AnyVariable + "' ORDER BY EmpName"))
{
using (SqlDataAdapter da = new SqlDataAdapter())
{
DataTable dt = new DataTable();
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
da.SelectCommand = cmd;
da.Fill(dt);
dt.Columns[0].ColumnName = "Employee Id";
dt.Columns[1].ColumnName = "Gender";
dt.Columns[2].ColumnName = "Employee Name";
dt.Columns[3].ColumnName = "On Hold";
return dt;
}
}
}
}
그리고 데이터 세트를 가져오는 다른 방법
public DataSet getDataSetExportToExcel()
{
DataSet ds = new DataSet();
DataTable dtEmp = new DataTable("CLOT List");
dtEmp = getAllList();
ds.Tables.Add(dtEmp);
ds.Tables[0].TableName = "Employee"; //If you which to use Mutliple Tabs
return ds;
}
[이벤트]버튼
protected void btn_Export_Click(object sender, EventArgs e)
{
DataSet ds = getDataSetExportToExcel();
using (XLWorkbook wb = new XLWorkbook())
{
wb.Worksheets.Add(ds);
wb.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
wb.Style.Font.Bold = true;
Response.Clear();
Response.Buffer = true;
Response.Charset = "";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=EmployeeonHoldList.xlsx");
using (MemoryStream MyMemoryStream = new MemoryStream())
{
wb.SaveAs(MyMemoryStream);
MyMemoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
}
}
이 답변을 추가하고 싶은 이유는 이 작업을 수행하기 위한 빠르고 신뢰성 높은 방법을 찾느라 많은 시간을 소비했기 때문입니다.또한 OpenXMLWriter를 사용한 완전한 예는 찾을 수 없었습니다.
첫째, COM/Interop(다른 많은 답변이 사용됨)은 이 목적을 위해 적합하지만 일부 민감성에 문제가 있습니다.수십 년 동안 사용해 왔고 대부분 안정적이지만 수백 명의 사용자에게 데이터 웨어하우스를 프런트엔드로 구현했을 때 머신과 사용자의 작업에 따라 문제가 너무 많다는 것을 알고 OpenXML로 전환했습니다. OpenXML DOM은 이 목적에 매우 적합하지만 OpenXMLWriter를 사용하는 것보다 속도가 느립니다.컬럼이 많은 대규모 데이터셋(100K+)에 들어가면 OpenXMLWriter보다 DOM이 훨씬 느리기 때문에 후자를 사용합니다.다음 방법에서는 30개 이상의 필드가 있는 420K 이상의 행을 30초 이내에 씁니다.
나는 그 논평이 누구나가 하고 있는 일을 안내하기에 충분하기를 바란다.모든 값을 문자열로 파일에 쓰기 때문에 단순하지만 데이터 내용을 기반으로 다양한 데이터 유형을 쓰기(및 다양한 셀 형식을 사용)하는 로직을 구현할 수 있습니다.또한 몇 가지 변경(열/행을 통한 루프)을 통해 DataTable 대신 DataGridView에서 사용할 수 있도록 조정할 수도 있습니다.
DocumentFormat에 대한 참조입니다.OpenXML(OpenXML SDK를 사용한d/l) 및 WindowsBase가 필요합니다.
Imports DocumentFormat.OpenXml
Imports DocumentFormat.OpenXml.Spreadsheet
Imports DocumentFormat.OpenXml.Packaging
Public Sub ExportToExcelXML(ByRef dt As DataTable, filename As String)
Dim wbp As WorkbookPart, wsp As WorksheetPart
'If this DataTable has more rows in it than can fit in Excel, throw an exception
If dt.Rows.Count > 1048575 Then Throw New Exception("The DataTable is too large to export to Excel.")
'Delete any previous file of the same name that may exist.
File.Delete(filename)
'Create an OpenXML SpreadsheetDocument...
Using xls = SpreadsheetDocument.Create(filename, SpreadsheetDocumentType.Workbook)
'Add a WorkbookPart to the Spreadsheet Doc, then add a WorksheetPart to the WorkbookPart.
wbp = xls.AddWorkbookPart()
wsp = wbp.AddNewPart(Of WorksheetPart)
'Now we need to add the "StyleSheet" to the WorkbookPart (that we just added above). This will allow us to apply formatting to our Cells.
'Add the WbStylesPart and the StyleSheet.
Dim stp As WorkbookStylesPart = wbp.AddNewPart(Of WorkbookStylesPart)
Dim ss As New Stylesheet
'Create the only two Fonts we're going to use (Regular and Bold).
Dim fBold As New Font
fBold.Append(New Bold)
Dim fnts As New Fonts
fnts.Append(New Font) 'This creates the default (unmodified, regular) Font. It's added first, so its index is 0.
fnts.Append(fBold) 'This creates the Bold font. It's added second, so its index is 1.
'Create the default Fill/Border settings (these have to be here, even though I don't set any custom fills/borders).
Dim flls As New Fills
Dim brdrs As New Borders
flls.Append(New Fill)
brdrs.Append(New Border)
'Now I have to add formats (NumberFormat and CellFormat). First, you create a NumberFormat. This is basically the pattern of
' the format (i.e. "@" for Text). For now, I only need a Text format, but I can add more patterns if needed.
' I give the format an ID of 164, since 163 is where the built-in Excel formats end.
Dim nbrfmts As New NumberingFormats
nbrfmts.Append(New NumberingFormat With {.NumberFormatId = 164, .FormatCode = "@"})
'Create the first two CellFormats: Default, which will have an index of 0 and "Header" (Bold/Centered) with an index of 1.
Dim cellfmts As New CellFormats()
cellfmts.Append(New CellFormat() With {.FontId = 0, .NumberFormatId = 164, .FillId = 0, .BorderId = 0})
cellfmts.Append(New CellFormat() With {.FontId = 1, .NumberFormatId = 164,
.Alignment = New Alignment() With {.WrapText = True, .Horizontal = HorizontalAlignmentValues.Center}})
'Add all of the Fonts/Fills/Borders/etc to the StyleSheet and add it all to the WorkbookStylesPart.
ss.Append(fnts)
ss.Append(flls)
ss.Append(brdrs)
ss.Append(cellfmts)
ss.NumberingFormats = nbrfmts
stp.Stylesheet = ss
stp.Stylesheet.Save()
'Now create an OpenXMLWriter using the WorksheetPart to write the cells to the worksheet.
Using oxw As OpenXmlWriter = OpenXmlWriter.Create(wsp)
'Write the start element for the Worksheet and the Columns...
oxw.WriteStartElement(New Worksheet)
oxw.WriteStartElement(New Columns())
'Now I'm going to loop through the columns in the DataTable...
For c As Integer = 0 To dt.Columns.Count - 1
'Now we'll get the width for the column. To do this, we loop through all of the rows and measure the width of the text
' using the default Excel Font (currently Font: Calibri Size: 11) and return the largest width (in pixels) to use below.
' Why not do this loop below (when I loop through the rows to write the Cells)? Because you can't. You have to
' write the Column XML first before writing the SheetData/Row/Cell XML (I confirmed this by trying it), so there's
' no way (that I'm aware of) to avoid looping through all of the rows twice if you want to AutoFit.
'Setup vars we'll use for getting the column widths (below).
Dim g = System.Drawing.Graphics.FromHwnd(IntPtr.Zero)
Dim fnt = New System.Drawing.Font("Calibri", 11)
Dim wid As Double = 0
'Get the width of the header (because if this is wider than the widest value, we'll use the header text's width).
' I found that adding 2 pixels to the width was necessary to get the column as wide as Excel would make it.
Dim tmp As Double = g.MeasureString(dt.Columns(c).ColumnName, New System.Drawing.Font(fnt, System.Drawing.FontStyle.Bold)).Width + 2
'Loop through the rows in the dt and get the width of the value in that row/col. If it's wider than the widest
' width we've encountered thus far, use the new wider width as our basis.
For Each row As DataRow In dt.Rows
If tmp > wid Then wid = tmp
tmp = g.MeasureString(row(c).ToString, fnt).Width
Next
'Set the column attributes and write it to the file. The Width is set using a formula that converts from pixels to Excel's column width values.
Dim oxa As New List(Of OpenXmlAttribute) From {New OpenXmlAttribute("min", Nothing, c + 1), New OpenXmlAttribute("max", Nothing, c + 1),
New OpenXmlAttribute("width", Nothing, System.Math.Round((wid - 12 + 5) / 7D + 1, 2))}
oxw.WriteStartElement(New Column(), oxa)
oxw.WriteEndElement()
Next
'CLose out the Columns collection.
oxw.WriteEndElement()
'Write the start element for the SheetData...
oxw.WriteStartElement(New SheetData)
'Write the start element for the Header row.
oxw.WriteStartElement(New Row)
'Loop through the Columns in the dt.
For Each col As DataColumn In dt.Columns
'Write a cell for this column's Header. All Header cells are written with a DataType of String ("str").
' I ALSO apply the "Header" CellFormat (StyleIndex 1) to all of the Header Cells. This makes them Bold and Centered.
WriteCell(oxw, col.ColumnName, "str", 1)
Next
'Close out the Header row.
oxw.WriteEndElement()
'Loop through all of the rows in the dt...
For Each row As DataRow In dt.Rows
'Write a StartElement for this row...
oxw.WriteStartElement(New Row)
'Loop through all of the columns in the dt...
For c As Integer = 0 To dt.Columns.Count - 1
'Write a value in this row/column to the Excel file. I use the datatype of "String" and the default CellFormat/StyleIndex.
WriteCell(oxw, row(c).ToString, "str", 0)
Next
'Close out this row.
oxw.WriteEndElement()
Next
'Close out the Worksheet and SheetData elements...
oxw.WriteEndElement()
oxw.WriteEndElement()
End Using
'Now we're going to create an OpenXMLWriter using the WorkbookPart (that we created above)...
Using oxw As OpenXmlWriter = OpenXmlWriter.Create(wbp)
'Add starting elements for the Workbook and Sheets collection.
oxw.WriteStartElement(New Workbook())
oxw.WriteStartElement(New Sheets())
'Add the Sheet (name the Sheet after the file name minus the extension).
oxw.WriteElement(New Sheet() With {.Name = Path.GetFileNameWithoutExtension(filename), .SheetId = 1, .Id = xls.WorkbookPart.GetIdOfPart(wsp)})
'Write End elements for the Workbook/Sheets
oxw.WriteEndElement()
oxw.WriteEndElement()
End Using
End Using
End Sub
'This Sub is used to write a value to a Cell using OpenXMLWriter.
Private Sub WriteCell(ByRef oxw As OpenXmlWriter, value As String, datatype As String, style As UInt32Value)
Dim oxa As New List(Of OpenXmlAttribute) From {New OpenXmlAttribute("t", Nothing, datatype), New OpenXmlAttribute("s", Nothing, style)}
oxw.WriteStartElement(New Cell(), oxa)
If value <> Nothing Then oxw.WriteElement(New CellValue(value))
oxw.WriteEndElement()
End Sub
Excel Interop:
이 방법은 날짜가 dd-mm-yyy에서 mm-dd-yyyy로 바뀌는 것을 방지합니다.
public bool DataTableToExcelFile(DataTable dt, string targetFile)
{
const bool dontSave = false;
bool success = true;
//Exit if there is no rows to export
if (dt.Rows.Count == 0) return false;
object misValue = System.Reflection.Missing.Value;
List<int> dateColIndex = new List<int>();
Excel.Application excelApp = new Excel.Application();
Excel.Workbook excelWorkBook = excelApp.Workbooks.Add(misValue);
Excel.Worksheet excelWorkSheet = excelWorkBook.Sheets("sheet1");
//Iterate through the DataTable and populate the Excel work sheet
try {
for (int i = -1; i <= dt.Rows.Count - 1; i++) {
for (int j = 0; j <= dt.Columns.Count - 1; j++) {
if (i < 0) {
//Take special care with Date columns
if (dt.Columns(j).DataType is typeof(DateTime)) {
excelWorkSheet.Cells(1, j + 1).EntireColumn.NumberFormat = "d-MMM-yyyy;@";
dateColIndex.Add(j);
}
//else if ... Feel free to add more Formats
else {
//Otherwise Format the column as text
excelWorkSheet.Cells(1, j + 1).EntireColumn.NumberFormat = "@";
}
excelWorkSheet.Cells(1, j + 1) = dt.Columns(j).Caption;
}
else if (dateColIndex.IndexOf(j) > -1) {
excelWorkSheet.Cells(i + 2, j + 1) = Convert.ToDateTime(dt.Rows(i).ItemArray(j)).ToString("d-MMM-yyyy");
}
else {
excelWorkSheet.Cells(i + 2, j + 1) = dt.Rows(i).ItemArray(j).ToString();
}
}
}
//Add Autofilters to the Excel work sheet
excelWorkSheet.Cells.AutoFilter(1, Type.Missing, Excel.XlAutoFilterOperator.xlAnd, Type.Missing, true);
//Autofit columns for neatness
excelWorkSheet.Columns.AutoFit();
if (File.Exists(exportFile)) File.Delete(exportFile);
excelWorkSheet.SaveAs(exportFile);
} catch {
success = false;
} finally {
//Do this irrespective of whether there was an exception or not.
excelWorkBook.Close(dontSave);
excelApp.Quit();
releaseObject(excelWorkSheet);
releaseObject(excelWorkBook);
releaseObject(excelApp);
}
return success;
}
날짜가 뒤집히는 것에 관심이 없다면 Excel 스프레드시트의 모든 셀을 코드 한 줄로 채우는 방법을 보여주는 링크를 사용하십시오.
CSV:
public string DataTableToCSV(DataTable dt, bool includeHeader, string rowFilter, string sortFilter, bool useCommaDelimiter = false, bool truncateTimesFromDates = false)
{
dt.DefaultView.RowFilter = rowFilter;
dt.DefaultView.Sort = sortFilter;
DataView dv = dt.DefaultView;
string csv = DataTableToCSV(dv.ToTable, includeHeader, useCommaDelimiter, truncateTimesFromDates);
//reset the Filtering
dt.DefaultView.RowFilter = string.Empty;
return csv;
}
public string DataTableToCsv(DataTable dt, bool includeHeader, bool useCommaDelimiter = false, bool truncateTimesFromDates = false)
{
StringBuilder sb = new StringBuilder();
string delimter = Constants.vbTab;
if (useCommaDelimiter)
delimter = ",";
if (includeHeader) {
foreach (DataColumn dc in dt.Columns) {
sb.AppendFormat("{0}" + Constants.vbTab, dc.ColumnName);
}
//remove the last Tab
sb.Remove(sb.ToString.Length - 1, 1);
sb.Append(Environment.NewLine);
}
foreach (DataRow dr in dt.Rows) {
foreach (DataColumn dc in dt.Columns) {
if (Information.IsDate(dr(dc.ColumnName).ToString()) & dr(dc.ColumnName).ToString().Contains(".") == false & truncateTimesFromDates) {
sb.AppendFormat("{0}" + delimter, Convert.ToDateTime(dr(dc.ColumnName).ToString()).Date.ToShortDateString());
} else {
sb.AppendFormat("{0}" + delimter, CheckDBNull(dr(dc.ColumnName).ToString().Replace(",", "")));
}
}
//remove the last Tab
sb.Remove(sb.ToString.Length - 1, 1);
sb.Append(Environment.NewLine);
}
return sb.ToString;
}
public enum enumObjectType
{
StrType = 0,
IntType = 1,
DblType = 2
}
public object CheckDBNull(object obj, enumObjectType ObjectType = enumObjectType.StrType)
{
object objReturn = null;
objReturn = obj;
if (ObjectType == enumObjectType.StrType & Information.IsDBNull(obj)) {
objReturn = "";
} else if (ObjectType == enumObjectType.IntType & Information.IsDBNull(obj)) {
objReturn = 0;
} else if (ObjectType == enumObjectType.DblType & Information.IsDBNull(obj)) {
objReturn = 0.0;
}
return objReturn;
}
이를 위한 한 가지 방법은 ACE OLEDB Provider(Excel 연결 문자열 참조)를 사용하는 것입니다.물론 프로바이더를 설치하고 등록해야 합니다.Excel이 설치되어 있다면 가지고 있을 것입니다만, 앱을 전개할 때 고려해야 할 사항입니다.
메서드를 입니다.ExportHelper
ExportHelper.CreateXlsFromDataTable(myDataTable, @"C:\tmp\export.xls");
ACE OLEDB를 사용하여 Excel 파일로 내보내기 위한 도우미:
public class ExportHelper
{
private const string ExcelOleDbConnectionStringTemplate = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=YES\";";
/// <summary>
/// Creates the Excel file from items in DataTable and writes them to specified output file.
/// </summary>
public static void CreateXlsFromDataTable(DataTable dataTable, string fullFilePath)
{
string createTableWithHeaderScript = GenerateCreateTableCommand(dataTable);
using (var conn = new OleDbConnection(String.Format(ExcelOleDbConnectionStringTemplate, fullFilePath)))
{
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
OleDbCommand cmd = new OleDbCommand(createTableWithHeaderScript, conn);
cmd.ExecuteNonQuery();
foreach (DataRow dataExportRow in dataTable.Rows)
{
AddNewRow(conn, dataExportRow);
}
}
}
private static void AddNewRow(OleDbConnection conn, DataRow dataRow)
{
string insertCmd = GenerateInsertRowCommand(dataRow);
using (OleDbCommand cmd = new OleDbCommand(insertCmd, conn))
{
AddParametersWithValue(cmd, dataRow);
cmd.ExecuteNonQuery();
}
}
/// <summary>
/// Generates the insert row command.
/// </summary>
private static string GenerateInsertRowCommand(DataRow dataRow)
{
var stringBuilder = new StringBuilder();
var columns = dataRow.Table.Columns.Cast<DataColumn>().ToList();
var columnNamesCommaSeparated = string.Join(",", columns.Select(x => x.Caption));
var questionmarkCommaSeparated = string.Join(",", columns.Select(x => "?"));
stringBuilder.AppendFormat("INSERT INTO [{0}] (", dataRow.Table.TableName);
stringBuilder.Append(columnNamesCommaSeparated);
stringBuilder.Append(") VALUES(");
stringBuilder.Append(questionmarkCommaSeparated);
stringBuilder.Append(")");
return stringBuilder.ToString();
}
/// <summary>
/// Adds the parameters with value.
/// </summary>
private static void AddParametersWithValue(OleDbCommand cmd, DataRow dataRow)
{
var paramNumber = 1;
for (int i = 0; i <= dataRow.Table.Columns.Count - 1; i++)
{
if (!ReferenceEquals(dataRow.Table.Columns[i].DataType, typeof(int)) && !ReferenceEquals(dataRow.Table.Columns[i].DataType, typeof(decimal)))
{
cmd.Parameters.AddWithValue("@p" + paramNumber, dataRow[i].ToString().Replace("'", "''"));
}
else
{
object value = GetParameterValue(dataRow[i]);
OleDbParameter parameter = cmd.Parameters.AddWithValue("@p" + paramNumber, value);
if (value is decimal)
{
parameter.OleDbType = OleDbType.Currency;
}
}
paramNumber = paramNumber + 1;
}
}
/// <summary>
/// Gets the formatted value for the OleDbParameter.
/// </summary>
private static object GetParameterValue(object value)
{
if (value is string)
{
return value.ToString().Replace("'", "''");
}
return value;
}
private static string GenerateCreateTableCommand(DataTable tableDefination)
{
StringBuilder stringBuilder = new StringBuilder();
bool firstcol = true;
stringBuilder.AppendFormat("CREATE TABLE [{0}] (", tableDefination.TableName);
foreach (DataColumn tableColumn in tableDefination.Columns)
{
if (!firstcol)
{
stringBuilder.Append(", ");
}
firstcol = false;
string columnDataType = "CHAR(255)";
switch (tableColumn.DataType.Name)
{
case "String":
columnDataType = "CHAR(255)";
break;
case "Int32":
columnDataType = "INTEGER";
break;
case "Decimal":
// Use currency instead of decimal because of bug described at
// http://social.msdn.microsoft.com/Forums/vstudio/en-US/5d6248a5-ef00-4f46-be9d-853207656bcc/localization-trouble-with-oledbparameter-and-decimal?forum=csharpgeneral
columnDataType = "CURRENCY";
break;
}
stringBuilder.AppendFormat("{0} {1}", tableColumn.ColumnName, columnDataType);
}
stringBuilder.Append(")");
return stringBuilder.ToString();
}
}
EPplus NuGet 패키지로 매우 간단합니다.
public class TestObject
{
public int Col1 { get; set; }
public int Col2 { get; set; }
public string Col3 { get; set; }
public DateTime Col4 { get; set; }
}
[TestMethod]
public void LoadFromCollection_MemberList_Test()
{
//https://stackoverflow.com/questions/32587834/epplus-loadfromcollection-text-converted-to-number/32590626#32590626
var TestObjectList = new List<TestObject>();
for (var i = 0; i < 10; i++)
TestObjectList.Add(new TestObject {Col1 = i, Col2 = i*10, Col3 = (i*10) + "E4"});
//Create a test file
var fi = new FileInfo(@"c:\temp\LoadFromCollection_MemberList_Test.xlsx");
if (fi.Exists)
fi.Delete();
using (var pck = new ExcelPackage(fi))
{
//Do NOT include Col1
var mi = typeof (TestObject)
.GetProperties()
.Where(pi => pi.Name != "Col1")
.Select(pi => (MemberInfo)pi)
.ToArray();
var worksheet = pck.Workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromCollection(
TestObjectList
, true
, TableStyles.Dark1
, BindingFlags.Public| BindingFlags.Instance
, mi);
pck.Save();
}
}
는 출력에 포함되지 않습니다.
여기 현명한 답변이 있습니다(Tomasz Winniewski, cuongle).래퍼/플러그인 라이브러리가 필요하거나 데이터를 최종적으로 쓰기 위해 셀별로 한 줄씩 루프해야 하는 두 가지 범주로 분류되는 것 같습니다.후자의 경우 성능이 느려지고, 데이터 테이블을 Excel로 내보내는 것과 같은 간단한 작업에는 아마도 첫 번째 작업이 그다지 편리하지 않을 것입니다.복사/붙여넣기 속도가 훨씬 빠릅니다(테스트할 때는 800행의 경우 3밀리초). 하지만 약간 부정행위를 해야 합니다.DataGridView가 내장된 숨겨진 양식을 즉시 생성해야 합니다.그런 다음 DataTable을 DataSource로 덤프하면 DataGridView 클래스의 "GetClipboardContent" 메서드를 호출하여 Excel 시트의 선택한 Range/Cell에 배치할 수 있습니다.코드 예:
private bool FncCopyDataTableToWorksheet(DataTable dt, ExcelUsing.Worksheet destWsh)
{
Form frm = new Form();
frm.Size = new Size(0, 0);
DataGridView dgv = new DataGridView();
DataObject obj;
ExcelUsing.Range rng;
int j = 0;
frm.Controls.Add(dgv);
bool result = false;
try
{
dgv.DataSource = dt;
dgv.RowHeadersVisible = false;
frm.Show();
dgv.SelectAll();
obj = dgv.GetClipboardContent();
frm.Hide();
dgv.ClearSelection();
if (obj != null)
{
Clipboard.SetDataObject(obj);
//Write Headers
foreach (DataGridViewColumn dgvc in dgv.Columns)
{
if (dgvc.Visible == true)
{
rng = (ExcelUsing.Range)destWsh.Cells[1, 1 + j];
rng.Value2 = dgvc.Name.ToString();
j++;
}
}
rng = (ExcelUsing.Range)destWsh.Cells[2, 1];
rng.Select();
destWsh.PasteSpecial(rng, _Missing, _Missing, _Missing, _Missing, _Missing, true);
result = true;
}
else { result = false; }
}
catch (Exception ex)
{
//Handle
}
rng = null;
obj = null;
dgv = null;
frm = null;
return result;
}
tuncalik의 답변에 대해서는, 특히 코드를 가지고 놀고 싶은 분은, 훌륭합니다.하지만, 그것은 제 날짜를 미국 형식으로 Excel로 변환하고 있습니다.영국에서는 2014년 3월 2일이 2014년 2월 3일입니다만, 미국에서는 2014년 3월 2일이 2014년 1일이면 다음 주 1일이 됩니다.영국 포맷으로 해야 하는데, 아이디어 있나요?
DataTable에 UK 형식으로 저장되어 있고 Excel도 UK로 설정되어 있는 것을 확인했습니다만, 어떠한 이유로 Excel 문서를 작성할 때는, USA라고 생각됩니다(이것은 Microsoft가 미국 기업이기 때문입니다).
문화 코드를 실험해 보겠습니다만, 아직 어디에 둘지 모르겠습니다.시도했지만 효과가 없었다.
추신.
아래와 같이 '캐스트'를 추가하여 작동시키기 위해 한 줄을 변경해야 했습니다.
// single worksheet
Excel._Worksheet workSheet = (Excel._Worksheet)excelApp.ActiveSheet;
업데이트: LongDateTime 형식으로 변환하여 날짜의 영국 포맷을 완료하였습니다.단, 이 포맷은 현재 유일한 작업입니다.
DateTime startDate = Convert.ToDateTime(myList[0].ToString());
string strStartDate = startDate.ToLongDateString();
DateTime endDate = Convert.ToDateTime(myList[myListTotalRows].ToString());
string strEndDate = endDate.ToLongDateString();
건배.
EasyX를 사용할 수 있습니다.Excel 파일을 내보내기 위한 라이브러리인 LS.
다음 코드를 확인합니다.
DataSet ds = new DataSet();
ds.Tables.Add(dataTable);
ExcelDocument xls = new ExcelDocument();
xls.easy_WriteXLSFile_FromDataSet("datatable.xls", ds,
new ExcelAutoFormat(Styles.AUTOFORMAT_EASYXLS1), "DataTable");
C#에서 데이터 테이블을 Excel로 내보내는 방법에 대해서는 이 샘플도 참조하십시오.
오래된 실 - 하지만 여기에 내 코드를 던져야겠다고 생각했다.지정된 경로(위치)에서 새로운 엑셀 시트에 데이터 테이블을 쓰는 작은 함수를 작성했습니다.또한 Microsoft Excel 14.0 라이브러리에 대한 참조를 추가해야 합니다.
이 스레드에서 엑셀을 쓰는 방법을 추출했습니다. 엑셀 파일에 데이터를 쓰는 방법(.xlsx)
데이터 테이블을 어떻게 쓸지 추측하기 위해 그걸 사용했어
* catch 스테이트먼트에는 에러 핸들러 스태틱클래스 참조가 있습니다(이러한 참조는 무시해도 됩니다).
using excel = Microsoft.Office.Interop.Excel;
using System.IO;
using System.Data;
using System.Runtime.InteropServices;
//class and namespace wrapper is not shown in this example
private void WriteToExcel(System.Data.DataTable dt, string location)
{
//instantiate excel objects (application, workbook, worksheets)
excel.Application XlObj = new excel.Application();
XlObj.Visible = false;
excel._Workbook WbObj = (excel.Workbook)(XlObj.Workbooks.Add(""));
excel._Worksheet WsObj = (excel.Worksheet)WbObj.ActiveSheet;
//run through datatable and assign cells to values of datatable
try
{
int row = 1; int col = 1;
foreach (DataColumn column in dt.Columns)
{
//adding columns
WsObj.Cells[row, col] = column.ColumnName;
col++;
}
//reset column and row variables
col = 1;
row++;
for (int i = 0; i < dt.Rows.Count; i++)
{
//adding data
foreach (var cell in dt.Rows[i].ItemArray)
{
WsObj.Cells[row, col] = cell;
col++;
}
col = 1;
row++;
}
WbObj.SaveAs(location);
}
catch (COMException x)
{
ErrorHandler.Handle(x);
}
catch (Exception ex)
{
ErrorHandler.Handle(ex);
}
finally
{
WbObj.Close();
}
}
다음 클래스를 이용하다
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using excel = Microsoft.Office.Interop.Excel;
using EL = ExcelLibrary.SpreadSheet;
using System.Drawing;
using System.Collections;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace _basic
{
public class ExcelProcesser
{
public void WriteToExcel(System.Data.DataTable dt)
{
excel.Application XlObj = new excel.Application();
XlObj.Visible = false;
excel._Workbook WbObj = (excel.Workbook)(XlObj.Workbooks.Add(""));
excel._Worksheet WsObj = (excel.Worksheet)WbObj.ActiveSheet;
object misValue = System.Reflection.Missing.Value;
try
{
int row = 1; int col = 1;
foreach (DataColumn column in dt.Columns)
{
//adding columns
WsObj.Cells[row, col] = column.ColumnName;
col++;
}
//reset column and row variables
col = 1;
row++;
for (int i = 0; i < dt.Rows.Count; i++)
{
//adding data
foreach (var cell in dt.Rows[i].ItemArray)
{
WsObj.Cells[row, col] = cell;
col++;
}
col = 1;
row++;
}
WbObj.SaveAs(fileFullName, excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
WbObj.Close(true, misValue, misValue);
}
}
}
}
이 솔루션은 기본적으로
List<Object>
데이터를 Excel로 전송하고 DataTable을 사용하여 이를 실현하기 위해 확장 방식을 구현했기 때문에 기본적으로 두 가지가 필요합니다. 1. 확장 방식.
public static class ReportHelper
{
public static string ToExcel<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
{
//table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
if (prop.Attributes[typeof(FGMS.Entity.Extensions.ReportHeaderAttribute)] != null)
{
table.Columns.Add(GetColumnHeader(prop), Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
}
}
//So it seems like when there is only one row of data the headers do not appear
//so adding a dummy blank row which fixed the issues
//Add a blank Row - Issue # 1471
DataRow blankRow = table.NewRow();
table.Rows.Add(blankRow);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
//row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
if (prop.Attributes[typeof(FGMS.Entity.Extensions.ReportHeaderAttribute)] != null)
{
row[GetColumnHeader(prop)] = prop.GetValue(item) ?? DBNull.Value;
}
table.Rows.Add(row);
}
table.TableName = "Results";
var filePath = System.IO.Path.GetTempPath() + "\\" + System.Guid.NewGuid().ToString() + ".xls";
table.WriteXml(filePath);
return filePath;
}
private static string GetColumnHeader(PropertyDescriptor prop)
{
return ((FGMS.Entity.Extensions.ReportHeaderAttribute)(prop.Attributes[typeof(FGMS.Entity.Extensions.ReportHeaderAttribute)])).ReportHeaderText;
}
}
- 속성을 사용하여 DTO 클래스를 꾸미다
[ReportHeaderAttribute("Column Name")]
public class UserDTO
{
public int Id { get; set; }
public int SourceId { get; set; }
public string SourceName { get; set; }
[ReportHeaderAttribute("User Type")]
public string UsereType { get; set; }
[ReportHeaderAttribute("Address")]
public string Address{ get; set; }
[ReportHeaderAttribute("Age")]
public int Age{ get; set; }
public bool IsActive { get; set; }
[ReportHeaderAttribute("Active")]
public string IsActiveString
{
get
{
return IsActive ? "Yes" : "No";
}
}}
엑셀의 컬럼이 되어야 하는 모든 것은 다음과 같이 장식되어야 한다.[ReportHeaderAttribute("Column Name")]
그럼 심플하게
Var userList = Service.GetUsers() //Returns List of UserDTO;
var excelFilePath = userList.ToExcel();
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(excelFilePath, FileMode.Open);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/vnd.ms-excel");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "UserList.xls" };
return result;
데이터를 Excel로 내보내려면 ClosedXML.Report 라이브러리(https://github.com/ClosedXML/ClosedXML.Report)를 사용합니다.정말이지, 이 도서관은 그녀가 사용하기 쉽고 멋진 도서관이야.라이브러리에는 Excel Interop이 필요하지 않습니다.ClosedXML.Report는 임의의 형식을 사용하여 Excel에서 작성할 수 있는 템플릿을 기반으로 Excel 파일을 생성합니다.예를 들어 다음과 같습니다.
var template = new XLTemplate(@".\Templates\report.xlsx");
using (var db = new DbDemos())
{
var cust = db.customers.LoadWith(c => c.Orders).First();
template.AddVariable(cust);
template.Generate();
}
template.SaveAs(outputFile);
Private tmr As System.Windows.Forms.Timer
Private Sub TestExcel() Handles Button1.Click
'// Initial data: SQL Server table with 6 columns and 293000 rows.
'// Data table holding all data
Dim dt As New DataTable("F161")
'// Create connection
Dim conn As New SqlConnection("Server=MYSERVER;Database=Test;Trusted_Connection=Yes;")
Dim fAdapter As New SqlDataAdapter With
{
.SelectCommand = New SqlCommand($"SELECT * FROM dbo.MyTable", conn)
}
'// Fill DataTable
fAdapter.Fill(dt)
'// Create Excel application
Dim xlApp As New Excel.Application With {.Visible = True}
'// Temporarily disable screen updating
xlApp.ScreenUpdating = False
'// Create brand new workbook
Dim xlBook As Excel.Workbook = xlApp.Workbooks.Add()
Dim xlSheet As Excel.Worksheet = DirectCast(xlBook.Sheets(1), Excel.Worksheet)
'// Get number of rows
Dim rows_count = dt.Rows.Count
'// Get number of columns
Dim cols_count = dt.Columns.Count
'// Here 's the core idea: after receiving data
'// you need to create an array and transfer it to sheet.
'// Why array?
'// Because it's the fastest way to transfer data to Excel's sheet.
'// So, we have two tasks:
'// 1) Create array
'// 2) Transfer array to sheet
'// =========================================================
'// TASK 1: Create array
'// =========================================================
'// In order to create array, we need to know that
'// Excel's Range object expects 2-D array whose lower bounds
'// of both dimensions start from 1.
'// This means you can't use C# array.
'// You need to manually create such array.
'// Since we already calculated number of rows and columns,
'// we can use these numbers in creating array.
Dim arr = Array.CreateInstance(GetType(Object), {rows_count, cols_count}, {1, 1})
'// Fill array
For r = 0 To rows_count - 1
For c = 0 To cols_count - 1
arr(r + 1, c + 1) = dt.Rows(r)(c)
Next
Next
'// =========================================================
'// TASK 2: Transfer array to sheet
'// =========================================================
'// Now we need to transfer array to sheet.
'// So, how transfer array to sheet fast?
'//
'// THE FASTEST WAY TO TRANSFER DATA TO SHEET IS TO ASSIGN ARRAY TO RANGE.
'// We could, of course, hard-code values, but Resize property
'// makes this work a breeze:
xlSheet.Range("A1").Resize.Resize(rows_count, cols_count).Value = arr
'// If we decide to dump data by iterating over array,
'// it will take LOTS of time.
'// For r = 1 To rows_count
'// For c = 1 To cols_count
'// xlSheet.Cells(r, c) = arr(r, c)
'// Next
'// Next
'// Here are time results:
'// 1) Assigning array to Range: 3 seconds
'// 2) Iterating over array: 45 minutes
'// Turn updating on
xlApp.ScreenUpdating = True
xlApp = Nothing
xlBook = Nothing
xlSheet = Nothing
'// Here we have another problem:
'// creating array took lots of memory (about 150 MB).
'// Using 'GC.Collect()', by unknown reason, doesn't help here.
'// However, if you run GC.Collect() AFTER this procedure is finished
'// (say, by pressing another button and calling another procedure),
'// then the memory is cleaned up.
'// I was wondering how to avoid creating some extra button to just release memory,
'// so I came up with the idea to use timer to call GC.
'// After 2 seconds GC collects all generations.
'// Do not forget to dispose timer since we need it only once.
tmr = New Timer()
AddHandler tmr.Tick,
Sub()
GC.Collect()
GC.WaitForPendingFinalizers()
GC.WaitForFullGCComplete()
tmr.Dispose()
End Sub
tmr.Interval = TimeSpan.FromSeconds(2).TotalMilliseconds()
tmr.Start()
End Sub
순수 샘플 코드(아이디어가 있는 사람에게 도움이 될 수 있는 경우)는, 여기서의 토마즈 비에니에프스키의 회답에 근거하고 있습니다.https://stackoverflow.com/a/21079709/2717521
메인 창 내보내기 버튼:
public int counter;
public void SaveToExcel(object sender, RoutedEventArgs e)
{
counter = 1;
CountChecker();
}
public void CountChecker()
{
string filename = GlobalStrings.building_house_address;
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\";
if (CurrentID != 0)
{
if (!File.Exists(path + filename + ".xlsx"))
{
DataGridParts.Export(path + filename);
MessageBoxEx.Show(this, "Shranjeno na namizje");
}
else
{
if (!File.Exists(path + "\\" + filename + " (" + (counter) + ")" + ".xlsx"))
{
DataGridParts.Export(path + filename + " (" + (counter) + ")");
MessageBoxEx.Show(this, "Shranjeno na namizje");
}
else
{
counter++;
CountChecker();
}
}
}
else
{
MessageBoxEx.Show(this, "Izbran ni noben naslov!");
}
}
ExportToExcel 클래스:
using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
namespace CBUGIS
{
public static class ExportToExcel
{
/// <summary>
/// Export DataTable to Excel file
/// </summary>
/// <param name="DataTable">Source DataTable</param>
/// <param name="ExcelFilePath">Path to result file name</param>
public static void Export(this System.Data.DataTable DataTable, string ExcelFilePath = null)
{
int ColumnsCount;
int RowShift = 5;
ColumnsCount = DataTable.Columns.Count;
// load excel, and create a new workbook
Application Excel = new Application();
Excel.Workbooks.Add();
// single worksheet
_Worksheet Worksheet = Excel.ActiveSheet;
Excel.Sheets[1].Name = "CBUGIS";
Worksheet.Columns.NumberFormat = "@";
Worksheet.Columns.HorizontalAlignment = XlHAlign.xlHAlignLeft;
object[,] Title = new object[3, 1]; // Array Size
if (GlobalStrings.building_alterantive_addresses.Length == 0)
{
if (GlobalStrings.building_postcode.Length != 0)
{
Title[0, 0] = "NASLOV: " + GlobalStrings.building_house_street + " " + GlobalStrings.building_house_number + GlobalStrings.building_house_id + ", " + GlobalStrings.building_postcode + " " + GlobalStrings.building_area;
Title[1, 0] = "K.O.: " + GlobalStrings.building_cadastral_community + ", ŠT.STAVBE: " + GlobalStrings.building_building_number + ", ŠT.PARCELE: " + GlobalStrings.building_plot_number;
}
else
{
Title[0, 0] = "NASLOV: " + GlobalStrings.building_house_street + " " + GlobalStrings.building_house_number + GlobalStrings.building_house_id;
Title[1, 0] = "K.O.: " + GlobalStrings.building_cadastral_community + ", ŠT.STAVBE: " + GlobalStrings.building_building_number + ", " + GlobalStrings.building_plot_number;
}
}
else
{
if (GlobalStrings.building_postcode.Length != 0)
{
Title[0, 0] = "NASLOV: " + GlobalStrings.building_house_street + " " + GlobalStrings.building_house_number + GlobalStrings.building_house_id + ", " + GlobalStrings.building_postcode + " " + GlobalStrings.building_area;
Title[1, 0] = "K.O.: " + GlobalStrings.building_cadastral_community + ", ŠT.STAVBE: " + GlobalStrings.building_building_number + ", ŠT.PARCELE: " + GlobalStrings.building_plot_number;
Title[2, 0] = "GLEJ TUDI: " + GlobalStrings.building_alterantive_addresses;
}
else
{
Title[0, 0] = "NASLOV: " + GlobalStrings.building_house_street + " " + GlobalStrings.building_house_number + GlobalStrings.building_house_id;
Title[1, 0] = "K.O.: " + GlobalStrings.building_cadastral_community + ", ŠT.STAVBE: " + GlobalStrings.building_building_number + ", ŠT.PARCELE: " + GlobalStrings.building_plot_number;
Title[2, 0] = "GLEJ TUDI: " + GlobalStrings.building_alterantive_addresses;
}
}
Range TitleRange = Worksheet.get_Range((Range)(Worksheet.Cells[3, 1]), (Range)(Worksheet.Cells[1, 1]));
TitleRange.Value = Title;
TitleRange.Font.Bold = true;
TitleRange.Font.Size = 10;
object[] Header = new object[11]; // Number of Columns
Header[0] = "DEL";
Header[1] = "DELEŽ";
Header[2] = "CRP";
Header[3] = "LASTNIK";
Header[4] = "NASLOV";
Header[5] = "P.Š";
Header[6] = "OBMOČJE";
Header[7] = "DRŽAVA";
Header[8] = "EMŠO/MAT. ŠT.";
Header[9] = "OPIS";
Header[10] = "OPOMBA";
Range HeaderRange = Worksheet.get_Range((Range)(Worksheet.Cells[RowShift, 2]), (Range)(Worksheet.Cells[RowShift, 12]));
HeaderRange.Value = Header;
HeaderRange.Font.Bold = true;
HeaderRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGray);
// DataCells
int RowsCount = DataTable.Rows.Count;
object[,] Cells = new object[RowsCount, ColumnsCount];
for (int j = 0; j < RowsCount; j++)
for (int i = 0; i < ColumnsCount - 1; i++)
if (i > 1)
{
Cells[j, i - 2] = DataTable.Rows[j][i];
}
Range CellRange = Worksheet.get_Range((Range)(Worksheet.Cells[RowShift +1, 2]), (Range)(Worksheet.Cells[RowShift + RowsCount, 12]));
CellRange.Value = Cells;
CellRange.Borders.LineStyle = XlLineStyle.xlContinuous;
Worksheet.Columns.NumberFormat = "@";
Worksheet.Columns[1].ColumnWidth = 0.1;
for (int b = 1; b < 12; b++)
{
if (b > 1)
{
Worksheet.Columns[b].AutoFit();
}
}
Worksheet.PageSetup.Orientation = XlPageOrientation.xlLandscape;
Worksheet.PageSetup.TopMargin = 0.5;
Worksheet.PageSetup.BottomMargin = 0.5;
Worksheet.PageSetup.RightMargin = 0.5;
Worksheet.PageSetup.LeftMargin = 0.5;
// check fielpath
if (ExcelFilePath != null && ExcelFilePath != "")
{
Worksheet.SaveAs(ExcelFilePath);
Excel.Quit();
Marshal.FinalReleaseComObject(Worksheet);
Marshal.FinalReleaseComObject(TitleRange);
Marshal.FinalReleaseComObject(HeaderRange);
Marshal.FinalReleaseComObject(CellRange);
Marshal.FinalReleaseComObject(Excel);
}
else
// no filepath is given
{
Excel.Visible = true;
}
}
}
}
Excel을 내보내는 간단한 방법은 Microsoft CloseXml 패키지를 사용하는 것입니다.쿼리 결과를 Excel 시트로 내보내기 위한 간단한 함수를 작성했습니다(용이지만 약간의 변경으로 Windows 어플리케이션에서 사용할 수 있습니다).
using ClosedXML.Excel;
...
public ActionResult ToExcel(List<Dictionary<string, string>> data, Dictionary<string, string> columnMap, string fileName, string sheetName)
{
var dtDataBuffer = new System.Data.DataTable("buffer");
foreach (string col in columnMap.Values)
{
dtDataBuffer.Columns.Add(col, typeof(string));
}
foreach (var row in data)
{
List<string> rowData = new List<string> { };
foreach (string col in columnMap.Keys)
{
rowData.Add(row[col]);
}
dtDataBuffer.Rows.Add(rowData.ToArray());
}
var memoryStream = new MemoryStream();
using (var workbook = new XLWorkbook())
{
var worksheet = workbook.Worksheets.Add(dtDataBuffer, sheetName);
worksheet.Rows().Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
worksheet.Rows().Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;
worksheet.Columns().AdjustToContents();
workbook.SaveAs(memoryStream);
}
return File(memoryStream.ToArray(), "application/vnd.ms-excel", fileName);
}
이것은 사용 예입니다(실제로 저는 쿼리를 실행하고 데이터를 생성하기 위해 자신의 클래스를 사용합니다).Oracle 및 SQL Server에 대해서는 다음 URL에서 확인할 수 있습니다.
public ActionResult myReportExport(){
var data=List<Dictionary<string, string>>(){
{{"Column1_Index","Column1_Value"},{"Column2_Index","Column2_Value"},...}
...
};
return ToExcel(data, new Dictionary<string, string> {
{ "Column1_Index", "Column1 Title" } ,
{ "Column2_Index", "Column2 Title" } ,
...
},
"myFileName.xlsx",
"my sheet name"
);
}
언급URL : https://stackoverflow.com/questions/8207869/how-to-export-datatable-to-excel
'code' 카테고리의 다른 글
Xcode 10.2.1 명령 PhaseScriptExecution이 0이 아닌 종료 코드로 실패했습니다. (0) | 2023.04.18 |
---|---|
UIButton 글꼴 크기를 너비에 맞게 조정 (0) | 2023.04.18 |
함수 또는 커스텀 함수를 통해 Excel에서 regex 지원을 받으려면 어떻게 해야 합니까? (0) | 2023.04.18 |
Swift에서 첫 번째 ViewController에서 탐색 모음을 숨기려면 어떻게 해야 합니까? (0) | 2023.04.18 |
Git에서 파일 이동/이름 변경 및 이력 유지가 가능합니까? (0) | 2023.04.18 |