Доступ к электронной таблице Excel с помощью С# иногда возвращает пустое значение для некоторых ячеек

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

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

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

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

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

Является ли это проблемой С# или проблемой Excel?

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

Спасибо заранее.

Ответ 1

Решение:

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

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

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

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

Синтаксис SQL SELECT * FROM [sheet1$]. То есть excel, а затем $ и завернутые в скобки [ ].

Важно:

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

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

Ответ 6

Решение:

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

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

Ответ 7

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

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

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

Вот какой код, который иллюстрирует это, и в качестве дополнительного бонуса даже 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.
                        }
                    }
                }
            }
        }
    }
}

Ответ 8

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

Ответ 9

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

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);

Ответ 10

Это не совсем правильно! По-видимому, Jet/ACE ALWAYS принимает строковый тип, если первые 8 строк пустые, независимо от IMEX = 1. Даже когда я сделал строки, считанные 0 в реестре, у меня была такая же проблема. Это был единственный надежный способ заставить его работать:

try
{
    Console.Write(wsReader.GetDouble(j).ToString());
}
catch   //Lame unfixable bug
{
    Console.Write(wsReader.GetString(j));
}

Код >