Запись массива в диапазон Excel

В настоящее время я пытаюсь записать данные из массива объектов в диапазон в Excel, используя следующий код, где objData - это всего лишь массив строк:

private object m = System.Type.Missing;
object[] objData = getDataIWantToWrite();

Range rn_Temp;
rn_Temp = (Range)XlApp.get_Range(RangeName, m);
rn_Temp = rn_Temp.get_Resize(objData.GetUpperBound(), 1);
rn_Temp.value2 = objData;

Это почти работает, проблема в том, что диапазон заполняется, но каждая ячейка получает значение первого элемента в objData.

Обратные произведения, т.е.

private object m = System.Type.Missing;
object[] objData = new object[x,y]

Range rn_Temp;
rn_Temp = (Range)XlApp.get_Range(RangeName, m);
rn_Temp = rn_Temp.get_Resize(objData.GetUpperBound(), 1);
objData = (object[])rn_Temp.value2;

вернет массив, содержащий все значения из рабочего листа, поэтому я не уверен, почему чтение и назначение работают по-другому.

Кто-нибудь когда-либо делал это успешно? В настоящее время я пишу ячейку массива по ячейке, но ей нужно справляться с большим количеством ( > 50 000) строк, и поэтому это занимает очень много времени.

Ответ 1

Это отрывок из моего метода, который преобразует DataTable (переменную dt) в массив, а затем записывает массив в Range на рабочем листе (wsh var). Вы также можете изменить переменную topRow на любую строку, в которую вы хотите поместить массив строк.

object[,] arr = new object[dt.Rows.Count, dt.Columns.Count];
for (int r = 0; r < dt.Rows.Count; r++)
{
    DataRow dr = dt.Rows[r];
    for (int c = 0; c < dt.Columns.Count; c++)
    {
        arr[r, c] = dr[c];
    }
}
Excel.Range c1 = (Excel.Range)wsh.Cells[topRow, 1];
Excel.Range c2 = (Excel.Range)wsh.Cells[topRow + dt.Rows.Count - 1, dt.Columns.Count];
Excel.Range range = wsh.get_Range(c1, c2);
range.Value = arr;

Конечно, вам не нужно использовать промежуточный DataTable, как я, выдержка из кода просто для демонстрации того, как массив может быть записан на лист за один вызов.

Ответ 2

Спасибо за парни-указатели - аргумент Value vs Value2 дал мне другой набор результатов поиска, которые помогли мне понять, что такое ответ. Кстати, свойство Value является параметризованным свойством, к которому необходимо получить доступ через accessor в С#. Они называются get_Value и set_Value и принимают необязательное значение enum. Если кто-то заинтересован, это объясняет это хорошо.

Возможно выполнить присвоение с помощью свойства Value2, что предпочтительнее, поскольку документация interop рекомендует использовать использование методов get_Value и set_Value по причинам, отличным от моего понимания.

Ключ, по-видимому, является размером массива объектов. Для вызова работы массив должен быть объявлен как двумерный, даже если вы назначаете только одномерные данные.

Я объявил свой массив данных как object[NumberofRows,1] и обработчик назначения работал.

Ответ 3

Вы можете поместить свои данные в набор записей и использовать Excel CopyFromRecordset Method - это намного быстрее, чем заполнение ячейки за ячейкой.

Вы можете создать набор записей из набора данных, используя этот код. Вам нужно будет сделать некоторые испытания, чтобы узнать, быстрее ли используется этот метод, чем то, что вы сейчас делаете.

Ответ 4

В моем случае программа запрашивает базу данных, которая возвращает DataGridView. Затем я копирую это в массив. Я получаю размер только что созданного массива, а затем записываю массив в электронную таблицу Excel. Этот код выводит более 5000 строк данных примерно через две секунды.

//private System.Windows.Forms.DataGridView dgvResults;
dgvResults.DataSource = DB.getReport();

Microsoft.Office.Interop.Excel.Application oXL;
Microsoft.Office.Interop.Excel._Workbook oWB;
Microsoft.Office.Interop.Excel._Worksheet oSheet;
try
{
    //Start Excel and get Application object.
    oXL = new Microsoft.Office.Interop.Excel.Application();
    oXL.Visible = true;

    oWB = (Microsoft.Office.Interop.Excel._Workbook)(oXL.Workbooks.Add(""));
    oSheet = (Microsoft.Office.Interop.Excel._Worksheet)oWB.ActiveSheet;

    var dgArray = new object[dgvResults.RowCount, dgvResults.ColumnCount+1];
    foreach (DataGridViewRow i in dgvResults.Rows)
    {
        if (i.IsNewRow) continue;
        foreach (DataGridViewCell j in i.Cells)
        {
            dgArray[j.RowIndex, j.ColumnIndex] = j.Value.ToString();
        }
    }

    Microsoft.Office.Interop.Excel.Range chartRange;

    int rowCount = dgArray.GetLength(0);
    int columnCount = dgArray.GetLength(1);
    chartRange = (Microsoft.Office.Interop.Excel.Range)oSheet.Cells[2, 1]; //I have header info on row 1, so start row 2
    chartRange = chartRange.get_Resize(rowCount, columnCount);
    chartRange.set_Value(Microsoft.Office.Interop.Excel.XlRangeValueDataType.xlRangeValueDefault, dgArray);


    oXL.Visible = false;
    oXL.UserControl = false;
    string outputFile = "Output_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx";

    oWB.SaveAs("c:\\temp\\"+outputFile, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookDefault, Type.Missing, Type.Missing,
        false, false, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

    oWB.Close();
}
catch (Exception ex)
{
    //...
}

Ответ 5

когда вы хотите написать 1D-массив в листе Excel , вам нужно транспонировать его и , вам не нужно создавать 2D-массив с 1 столбцом ([n, 1] ), как я читал выше! Вот пример кода:

 wSheet.Cells(RowIndex, colIndex).Resize(RowsCount, ).Value = _excel.Application.transpose(My1DArray)

Хорошего дня, Жиль

Ответ 6

По какой-то причине преобразование в двумерный массив не сработало для меня. Но следующий подход:

public void SetRow(Range range, string[] data)
{
    range.get_Resize(1, data.Length).Value2 = data;
}

Ответ 7

Тип определения массива кажется ключом: В моем случае это массив одного измерения из 17 элементов, которые должны быть преобразованы в двухмерный массив

Определение столбцов: object [,] Array = новый объект [17, 1];

Определение строк object [,] Array = новый объект [1,17];

Код для значения2 в обоих случаях тот же           Excel.Range cell = activeWorksheet.get_Range (Диапазон);           cell.Value2 = Array;

LG Georg

Ответ 8

Vb.NET

    Dim dt As System.Data.DataTable = myDataTable
    Dim dc As System.Data.DataColumn
    Dim colIndex As Integer = 0
    Dim rowIndex As Integer = 0

    'Rows Count
    Dim size As Integer = dt.Rows.Count

    For Each dc In dt.Columns
        colIndex = colIndex + 1
        'Header Title
        wSheet.Cells(1, colIndex) = dc.ColumnName
        'All Colunm data
        wSheet.Cells(2, colIndex).Resize(size, ).Value = _excel.Application.transpose(dt.Rows.OfType(Of DataRow)().[Select](Function(k) IIf(IsDBNull(CObj(k(dc.ColumnName))), "", CObj(k(dc.ColumnName)))).ToArray())
    Next