Доступ к электронной таблице Excel с помощью C # иногда возвращает пустое значение для некоторых ячеек - PullRequest
11 голосов
/ 18 ноября 2008

Мне нужно получить доступ к электронной таблице Excel и вставить данные из электронной таблицы в базу данных SQL. Однако первичные ключи смешанные, большинство из них цифровые, а некоторые буквенно-цифровые.

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

Я использую метод OleDb для доступа к файлу Excel. После извлечения данных с помощью командной строки я помещаю данные в DataAdapter, а затем заполняю DataSet. Я перебираю все строки (dr) в первой таблице данных в наборе данных.

Я ссылаюсь на столбцы, используя dr ["..."]. ToString ()

Если я отлаживаю проект в Visual Studio 2008 и вижу «расширенные свойства», удерживая мышь над «dr», я могу просмотреть значения DataRow, но первичный ключ, который должен быть буквенно-цифровым, {}. Другие значения заключены в кавычки, но пустое значение имеет фигурные скобки.

Это проблема C # или Excel?

Кто-нибудь когда-либо сталкивался с этой проблемой раньше, или, может быть, нашел решение / исправить?

Заранее спасибо.

Ответы [ 10 ]

26 голосов
/ 10 августа 2009

Решение:

Строка подключения:

Provider = Microsoft.Jet.OLEDB.4.0; Источник данных = FilePath; Расширенный Свойства = "Excel 8.0; HDR = Да; IMEX = 1";

  1. HDR=Yes; указывает, что первая строка содержит имена столбцов, а не данные. HDR=No; указывает на обратное.

  2. IMEX=1; велит драйверу всегда читать «смешанные» (числа, даты, строки и т. Д.) Столбцы данных в виде текста. Обратите внимание, что этот параметр может повлиять на отрицательный доступ к записи на листе Excel.

Синтаксис SQL SELECT * FROM [sheet1$]. То есть Имя листа Excel, сопровождаемое $ и заключенное в скобки [ ].

Важно:

  • Проверьте [HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Jet \ 4.0 \ Engines \ Excel] реестр реестра REG_DWORD "TypeGuessRows". Это ключ к тому, чтобы Excel не использовал только первые 8 строк, чтобы угадать тип данных столбцов. Установите это значение в 0 для сканирования всех строк. Это может ухудшить производительность.

  • Если рабочая книга Excel защищена паролем, вы не можете открыть ее для доступа к данным, даже указав правильный пароль в строке подключения. Если вы попытаетесь, вы получите следующее сообщение об ошибке: «Не удалось расшифровать файл».

3 голосов
/ 05 марта 2009

Источник данных Excel выбирает тип столбца для всего столбца. Если одна из ячеек не точно соответствует этому типу, она оставляет такие пробелы. У нас были проблемы, когда наша машинистка вводила «8» (пробел перед числом, поэтому Excel преобразовал его в строку для этой ячейки) в числовом столбце. Для меня будет иметь смысл попробовать методы .Net Parse, так как они более устойчивы, но я полагаю, что драйвер Excel работает не так.

Наше исправление, поскольку мы использовали службы импорта баз данных, заключалось в регистрации всех строк, которые «провалились» таким образом. Затем мы вернулись к документу XLS и перепечатали эти ячейки, чтобы убедиться, что базовый тип был правильным. (Мы обнаружили, что удаление пробела не устранило его - сначала нужно было очистить всю ячейку, а затем набрать «8»). Чувствует себя хакером и не уныло, но это был лучший метод, который мы нашли. Если драйвер Excel не может правильно прочитать его самостоятельно, вы ничего не можете сделать, чтобы получить эти данные, как только вы окажетесь в .Net.

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

1 голос
/ 25 октября 2011

Упорядочить записи в файле xls по коду ascii в порядке убывания, чтобы буквенно-цифровые поля отображались вверху под строкой заголовка. Это гарантирует, что первая строка считанных данных будет определять тип данных как «varchar» или «nvarchar»

1 голос
/ 09 сентября 2010

Я ответил на аналогичный вопрос здесь . Здесь я скопировал и вставил один и тот же ответ для вашего удобства:

У меня была такая же проблема, но я смог обойти ее, не прибегая к интерфейсу Excel COM или стороннему программному обеспечению. Это требует немного дополнительной обработки, но, похоже, работает на меня.

  1. Сначала прочитайте данные, чтобы получить имена столбцов
  2. Затем создайте новый DataSet с каждым из этих столбцов, установив для каждого из их DataTypes строку.
  3. Считайте данные снова в этот новый набор данных. Вуаля - научная нотация исчезла, и все читается как строка.

Вот некоторый код, который иллюстрирует это, и в качестве дополнительного бонуса, он даже StyleCopped!

public void ImportSpreadsheet(string path)
{
    string extendedProperties = "Excel 12.0;HDR=YES;IMEX=1";
    string connectionString = string.Format(
        CultureInfo.CurrentCulture,
        "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"{1}\"",
        path,
        extendedProperties);

    using (OleDbConnection connection = new OleDbConnection(connectionString))
    {
        using (OleDbCommand command = connection.CreateCommand())
        {
            command.CommandText = "SELECT * FROM [Worksheet1$]";
            connection.Open();

            using (OleDbDataAdapter adapter = new OleDbDataAdapter(command))
            using (DataSet columnDataSet = new DataSet())
            using (DataSet dataSet = new DataSet())
            {
                columnDataSet.Locale = CultureInfo.CurrentCulture;
                adapter.Fill(columnDataSet);

                if (columnDataSet.Tables.Count == 1)
                {
                    var worksheet = columnDataSet.Tables[0];

                    // Now that we have a valid worksheet read in, with column names, we can create a
                    // new DataSet with a table that has preset columns that are all of type string.
                    // This fixes a problem where the OLEDB provider is trying to guess the data types
                    // of the cells and strange data appears, such as scientific notation on some cells.
                    dataSet.Tables.Add("WorksheetData");
                    DataTable tempTable = dataSet.Tables[0];

                    foreach (DataColumn column in worksheet.Columns)
                    {
                        tempTable.Columns.Add(column.ColumnName, typeof(string));
                    }

                    adapter.Fill(dataSet, "WorksheetData");

                    if (dataSet.Tables.Count == 1)
                    {
                        worksheet = dataSet.Tables[0];

                        foreach (var row in worksheet.Rows)
                        {
                            // TODO: Consume some data.
                        }
                    }
                }
            }
        }
    }
}
1 голос
/ 03 сентября 2009

Решение:

  1. Вы ставите HDR = Нет, чтобы первая строка не считалась заголовком столбца. Строка подключения: Provider = Microsoft.Jet.OLEDB.4.0; Источник данных = FilePath; Расширенные свойства = "Excel 8.0; HDR = Нет; IMEX = 1";
  2. Вы игнорируете первую строку и получаете доступ к данным любым удобным для вас способом (DataTable, DataReader и т. Д.). Доступ к столбцам осуществляется по числовым индексам вместо имен столбцов.

Это сработало для меня. Таким образом, вам не нужно изменять регистры!

1 голос
/ 18 февраля 2009

Для совместимости с VISTA вы можете использовать драйвер EXCEL 12.0 в строке подключения. Это должно решить вашу проблему. Это сделал мой.

1 голос
/ 19 ноября 2008

ItemArray - это объектный массив. Поэтому я предполагаю, что «столбец» в DataRow, на который я пытаюсь ссылаться, имеет тип object.

1 голос
/ 18 ноября 2008

{} означает, что это какой-то пустой объект, а не строка. Когда вы наводите курсор на объект, вы должны увидеть его тип. Аналогично, когда вы используете quickwatch для просмотра dr ["..."], вы должны увидеть тип объекта. Какой тип объекта вы получаете?

0 голосов
/ 16 июля 2012

Это не совсем правильно! Очевидно, что Jet / ACE ВСЕГДА принимает строковый тип, если первые 8 строк пусты, независимо от IMEX = 1. Даже когда я сделал записи, считанные в реестре до 0, у меня все еще была та же проблема. Это был единственный верный способ заставить его работать: </p> <pre><code>try { Console.Write(wsReader.GetDouble(j).ToString()); } catch //Lame unfixable bug { Console.Write(wsReader.GetString(j)); }

0 голосов
/ 13 мая 2011

привет, весь этот код получает также буквенно-цифровые значения

using System.Data.OleDb;

string ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + filepath + ";" + "Extended Properties="+(char)34+"Excel 8.0;IMEX=1;"+(char)34;

string CommandText = "select * from [Sheet1$]";

OleDbConnection myConnection = new OleDbConnection(ConnectionString);
myConnection.Open();

OleDbDataAdapter myAdapter = new OleDbDataAdapter(CommandText, myConnection);

ds = null;
ds = new DataSet();
myAdapter.Fill(ds);
...