J'essaie de lire un fichier Excel dans une liste de Data.DataTable, bien qu'avec ma méthode actuelle cela puisse prendre très longtemps. Je vais essentiellement feuille de travail par feuille de travail, cellule par cellule, et cela prend généralement beaucoup de temps. Y at-il un moyen plus rapide de faire cela? Voici mon code:
List<DataTable> List = new List<DataTable>();
// Counting sheets
for (int count = 1; count < WB.Worksheets.Count; ++count)
{
// Create a new DataTable for every Worksheet
DATA.DataTable DT = new DataTable();
WS = (Excel.Worksheet)WB.Worksheets.get_Item(count);
textBox1.Text = count.ToString();
// Get range of the worksheet
Range = WS.UsedRange;
// Create new Column in DataTable
for (cCnt = 1; cCnt <= Range.Columns.Count; cCnt++)
{
textBox3.Text = cCnt.ToString();
Column = new DataColumn();
Column.DataType = System.Type.GetType("System.String");
Column.ColumnName = cCnt.ToString();
DT.Columns.Add(Column);
// Create row for Data Table
for (rCnt = 0; rCnt <= Range.Rows.Count; rCnt++)
{
textBox2.Text = rCnt.ToString();
try
{
cellVal = (string)(Range.Cells[rCnt, cCnt] as Excel.Range).Value2;
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
{
ConvertVal = (double)(Range.Cells[rCnt, cCnt] as Excel.Range).Value2;
cellVal = ConvertVal.ToString();
}
// Add to the DataTable
if (cCnt == 1)
{
Row = DT.NewRow();
Row[cCnt.ToString()] = cellVal;
DT.Rows.Add(Row);
}
else
{
Row = DT.Rows[rCnt];
Row[cCnt.ToString()] = cellVal;
}
}
}
// Add DT to the list. Then go to the next sheet in the Excel Workbook
List.Add(DT);
}
Caling .Value2
est une opération coûteuse car il s'agit d'un appel COM-interop. Je voudrais plutôt lire toute la plage dans un tableau, puis parcourir le tableau:
object[,] data = Range.Value2;
// Create new Column in DataTable
for (int cCnt = 1; cCnt <= Range.Columns.Count; cCnt++)
{
textBox3.Text = cCnt.ToString();
var Column = new DataColumn();
Column.DataType = System.Type.GetType("System.String");
Column.ColumnName = cCnt.ToString();
DT.Columns.Add(Column);
// Create row for Data Table
for (int rCnt = 1; rCnt <= Range.Rows.Count; rCnt++)
{
textBox2.Text = rCnt.ToString();
string CellVal = String.Empty;
try
{
cellVal = (string)(data[rCnt, cCnt]);
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
{
ConvertVal = (double)(data[rCnt, cCnt]);
cellVal = ConvertVal.ToString();
}
DataRow Row;
// Add to the DataTable
if (cCnt == 1)
{
Row = DT.NewRow();
Row[cCnt.ToString()] = cellVal;
DT.Rows.Add(Row);
}
else
{
Row = DT.Rows[rCnt + 1];
Row[cCnt.ToString()] = cellVal;
}
}
}
Si quelqu'un d'autre utilise EPPlus. Cette implémentation est assez naïve, mais certains commentaires attirent l’attention sur de tels sujets. Si vous superposiez une méthode GetWorkbookAsDataSet()
de plus, cela ferait ce que l'OP demande.
/// <summary>
/// Assumption: Worksheet is in table format with no weird padding or blank column headers.
///
/// Assertion: Duplicate column names will be aliased by appending a sequence number (eg. Column, Column1, Column2)
/// </summary>
/// <param name="worksheet"></param>
/// <returns></returns>
public static DataTable GetWorksheetAsDataTable(ExcelWorksheet worksheet)
{
var dt = new DataTable(worksheet.Name);
dt.Columns.AddRange(GetDataColumns(worksheet).ToArray());
var headerOffset = 1; //have to skip header row
var width = dt.Columns.Count;
var depth = GetTableDepth(worksheet, headerOffset);
for (var i = 1; i <= depth; i++)
{
var row = dt.NewRow();
for (var j = 1; j <= width; j++)
{
var currentValue = worksheet.Cells[i + headerOffset, j].Value;
//have to decrement b/c Excel is 1 based and datatable is 0 based.
row[j - 1] = currentValue == null ? null : currentValue.ToString();
}
dt.Rows.Add(row);
}
return dt;
}
/// <summary>
/// Assumption: There are no null or empty cells in the first column
/// </summary>
/// <param name="worksheet"></param>
/// <returns></returns>
private static int GetTableDepth(ExcelWorksheet worksheet, int headerOffset)
{
var i = 1;
var j = 1;
var cellValue = worksheet.Cells[i + headerOffset, j].Value;
while (cellValue != null)
{
i++;
cellValue = worksheet.Cells[i + headerOffset, j].Value;
}
return i - 1; //subtract one because we're going from rownumber (1 based) to depth (0 based)
}
private static IEnumerable<DataColumn> GetDataColumns(ExcelWorksheet worksheet)
{
return GatherColumnNames(worksheet).Select(x => new DataColumn(x));
}
private static IEnumerable<string> GatherColumnNames(ExcelWorksheet worksheet)
{
var columns = new List<string>();
var i = 1;
var j = 1;
var columnName = worksheet.Cells[i, j].Value;
while (columnName != null)
{
columns.Add(GetUniqueColumnName(columns, columnName.ToString()));
j++;
columnName = worksheet.Cells[i, j].Value;
}
return columns;
}
private static string GetUniqueColumnName(IEnumerable<string> columnNames, string columnName)
{
var colName = columnName;
var i = 1;
while (columnNames.Contains(colName))
{
colName = columnName + i.ToString();
i++;
}
return colName;
}
S'il vous plaît consulter les liens ci-dessous
http://www.codeproject.com/Questions/376355/import-MS-Excel-to-datatable (6 solutions affichées)
Meilleur/Le plus rapide moyen de lire une feuille Excel dans un DataTable?
MS Office Interop est lent et même Microsoft ne recommande pas l'utilisation d'Interop sur le serveur et ne peut pas être utilisé pour importer des fichiers Excel volumineux. Pour plus de détails, voir pourquoi ne pas utiliser OLE Automation du point de vue de Microsoft.
Au lieu de cela, vous pouvez utiliser n’importe quelle bibliothèque Excel, telle que EasyXLS par exemple. Ceci est un exemple de code qui montre comment lire le fichier Excel:
ExcelDocument workbook = new ExcelDocument();
DataSet ds = workbook.easy_ReadXLSActiveSheet_AsDataSet("Excel.xls");
DataTable dataTable = ds.Tables[0];
Si votre fichier Excel contient plusieurs feuilles ou que vous importez uniquement des plages de cellules (pour de meilleures performances), jetez un œil à plusieurs exemples de code sur comment importer Excel vers DataTable en C # avec EasyXLS .
Dim sSheetName As String
Dim sConnection As String
Dim dtTablesList As DataTable
Dim oleExcelCommand As OleDbCommand
Dim oleExcelReader As OleDbDataReader
Dim oleExcelConnection As OleDbConnection
sConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Test.xls;Extended Properties=""Excel 12.0;HDR=No;IMEX=1"""
oleExcelConnection = New OleDbConnection(sConnection)
oleExcelConnection.Open()
dtTablesList = oleExcelConnection.GetSchema("Tables")
If dtTablesList.Rows.Count > 0 Then
sSheetName = dtTablesList.Rows(0)("TABLE_NAME").ToString
End If
dtTablesList.Clear()
dtTablesList.Dispose()
If sSheetName <> "" Then
oleExcelCommand = oleExcelConnection.CreateCommand()
oleExcelCommand.CommandText = "Select * From [" & sSheetName & "]"
oleExcelCommand.CommandType = CommandType.Text
oleExcelReader = oleExcelCommand.ExecuteReader
nOutputRow = 0
While oleExcelReader.Read
End While
oleExcelReader.Close()
End If
oleExcelConnection.Close()
class DataReader
{
Excel.Application xlApp;
Excel.Workbook xlBook;
Excel.Range xlRange;
Excel.Worksheet xlSheet;
public DataTable GetSheetDataAsDataTable(String filePath, String sheetName)
{
DataTable dt = new DataTable();
try
{
xlApp = new Excel.Application();
xlBook = xlApp.Workbooks.Open(filePath);
xlSheet = xlBook.Worksheets[sheetName];
xlRange = xlSheet.UsedRange;
DataRow row=null;
for (int i = 1; i <= xlRange.Rows.Count; i++)
{
if (i != 1)
row = dt.NewRow();
for (int j = 1; j <= xlRange.Columns.Count; j++)
{
if (i == 1)
dt.Columns.Add(xlRange.Cells[1, j].value);
else
row[j-1] = xlRange.Cells[i, j].value;
}
if(row !=null)
dt.Rows.Add(row);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
xlBook.Close();
xlApp.Quit();
}
return dt;
}
}