2017-02-13 3 views
0

Я пытаюсь прочитать некоторые значения из нескольких файлов и сохранить их в новом .xlsx файле с другой группировкой. Я разработал очень простую установку для тестирования различного форматирования и поведения с нулевыми значениями. Я всегда открываю только что созданный файл в Excel, чтобы увидеть результат. Пока нет проблем.Excel: Потеря десятичного разделителя при преобразовании из строк в число

Однако в моем тестовом случае я могу достичь: A) сохранить тестовые значения, как они есть (строки) или B) заставить Excel рассматривать их как числа с заданным форматом (хорошие), но потерять десятичный разделитель (очень плохой & странный).

Я проследил проблему до последней строки в фрагменте кода ниже. Идея самоназначения - это другая должность где-то здесь, в SO, но сейчас я не могу ее найти.

Если строка закомментирована, результаты аналогичны string[,] contents, но они форматируются как текст (и Excel жалуется на это сообщением «номер, отформатированный как текст»). Если я раскомментирую это, числа считаются числами, но теряют десятичные разделители. Также проблема может быть фактом, что я нахожусь в Чехии, а десятичный разделитель - ,, что может вызвать проблемы с Excel. Более того, чтение значений от начала до double[,] contents отсутствует, так как мне нужно указать, отсутствует ли значение (с пустой ячейкой). И double?[,] contents сбой Excel ...

Пожалуйста, вы не встречали это поведение раньше? Я хотел бы 1) уметь указывать отсутствующее значение и 2) иметь содержимое ячеек, отформатированных как число, а не текст. Можете ли вы помочь мне, как достичь этого?

excelApp = new Excel.Application(); 
excelWorkBooks = excelApp.Workbooks; 
excelWorkBook = excelWorkBooks.Add(); 
excelSheets = excelWorkBook.Sheets; 
excelWorkSheet = excelSheets[1];   //Beware! Excel is one-based as opposed to a zero-based C# 

string[,] contents = new string[,] { { "1,23", "2,123123123", "3,1415926535" }, { "2,15", null, "" } }; 

int contentsHeight = contents.GetLength(0); 
int contentsWidth = contents.GetLength(1); 

System.Globalization.CultureInfo currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture; 
string numberFormat = string.Format("0" + currentCulture.NumberFormat.NumberDecimalSeparator + "00E+00"); 

for (int column = 0; column < contentsWidth; column++) { 
    excelWorkSheet.Columns[column + 1].NumberFormat = numberFormat; 
} 

Excel.Range range = excelWorkSheet.Range[excelWorkSheet.Cells[1, 1], excelWorkSheet.Cells[contentsHeight, contentsWidth]]; 
range.Value = contents; 
// range.Value = range.Value; //Problematic place 

EDIT: Я судимый изменить NumberFormat от 0,00E+00 к чему-то вроде 0,0, 0.0, #,# ради теста, но без успеха. Любая авария (десятичная точка) или остается в виде текста.

+0

Это не имеет никакого отношения к Excel. Вы пытаетесь передать строки, отформатированные для неправильной локали. Десятичная численность в странах Англосаксона - '.'. В вашем примере используется ',', обычно используемое в европейских странах. Держу пари, что ваш язык не французский, ни немецкий, ни греческий. –

+0

* Вместо того, чтобы пытаться жестко закодировать разделитель, передайте числа как * numbers *. т.е. использовать десятичный или двойной массив и передать значения * неформатированные * в Excel. Он * может * принимать числа, а также текст –

+0

Даже вместо того, чтобы использовать interop, используйте библиотеку типа Epplus для создания корректного файла 'xlsx', даже без установки Excel. Вы можете заполнить лист 'sheet.LoadFromCollection (myNumbersCollection)' или 'LoadFromDataTable'. –

ответ

0

Нет необходимости конвертировать числа в текст, прежде чем записывать их в ячейку. Excel понимает числа. Еще одна проблема заключается в том, что код пытается установить массив как значение целого диапазона, как если бы он вставлялся в Excel.

Можно установить номера, даже аннулирует, непосредственно с помощью простого цикла, например

double?[,] contents = new double?[,] { { 1.23, 2.123123123, 3.1415926535 }, 
             { 2.15, null, null } }; 
int contentsHeight = contents.GetLength(0); 
int contentsWidth = contents.GetLength(1); 
... 
for(int i=0;i<= contentsHeight; i++) 
    for (int j = 0; j <= contentsWidth; j++) 
     excelWorkSheet.Cells[i+1,j+1].Value = contents[i,j]; 

Вместо использования Excel через Interop, хотя, это лучше использовать пакет как EPPlus генерировать xlsx файлы напрямую, без Excel установлен. Это позволяет создавать реальные файлы Excel даже на веб-серверах, где установка Excel невозможна.

Код для этой конкретной задачи будет аналогичен:

var file = new FileInfo("test.xlsx"); 
using (var pck = new ExcelPackage(file)) 
{ 
    var ws = pck.Workbook.Worksheets.Add("Rules"); 
    for(int i=0;i<= contentsHeight; i++) 
     for (int j = 0; j <= contentsWidth; j++) 
      ws.Cells[i+1,j+1].Value = contents[i,j]; 
    pck.Save(); 
} 

EPPlus имеет некоторые удобные методы, которые делают погрузочную лист легко, например, LoadFromDataTable или LoadFromCollection. Если данные пришли из DataTable, создавая лист будет столь же просто, как:

var file = new FileInfo("test.xlsx"); 
using (var pck = new ExcelPackage(file)) 
{ 
    var ws = pck.Workbook.Worksheets.Add("Rules"); 
    ws.LoadFromDataTable(myTable); 
    pck.Save(); 
} 

LoadFromDataTable возвращает ExcelRange, который позволяет форматирование ячейки так же, как Excel Interop.

+0

Я надеялся решить это, не поддавшись на каждую ячейку, так как я пишу 14 листов каждые 5 колонок раз 4500 строк. Что касается скорости, проконсультируйтесь с этим: http://www.clear-lines.com/blog/post/Write-data-to-an-Excel-worksheet-with-C-fast.aspx. Однако, если мне нужно работать на основе ячеек, я могу сделать это непосредственно в Excel. Доступность в Интернете - это не то, о чем я забочусь, а так как это для внутреннего использования, где практически все компьютеры имеют Excel ... – Rao

+0

Interop * * * медленнее, чем генерировать файл напрямую. Если вы заботитесь о производительности, вы не должны использовать interop в первую очередь. Если вы хотите сгенерировать * отчеты *, вы должны использовать, например, службы Reporting Services или SSIS. –

+0

Где вы загружаете данные? Если данные загружаются из базы данных, например, в качестве DataTable, вы можете просто использовать LoadFromDataTable 15 раз. Существует также «LoadFromDataReader» для загрузки непосредственно с устройства быстрой перемотки вперед –

Смежные вопросы