.NetでExcelからインポートする場合の科学表記法
質問
Excelからデータをインポートして処理するC#/。Netジョブがあります。クライアントがファイルをドロップして処理します(元のファイルを制御できないため重要です)。
OleDbライブラリを使用してデータセットを埋めます(そのコードを書くのは嫌いです。まじめな話、.Net開発者がそれ以上書くのを恐れるコードはありますか?)。ファイルには30829300、30071500などの数字が含まれています。これらの列のデータ型は「テキスト」です
これらの数値は、データをインポートするときに科学表記法に変換されます。とにかくこれを防ぐ方法はありますか?
-クリス
解決
OleDbライブラリは、多くの場合、Excelスプレッドシートのデータを台無しにします 。これは主に、各列の最初の8つのセルの値から各列の型で guessing をすべて固定型列レイアウトに強制するためです。推測が間違っている場合は、数字列が科学表記に変換されてしまいます。 Blech!
これを回避するには、OleDbをスキップして、シートを直接自分で読んでください。これを行うには、ExcelのCOMインターフェイス(これもblech!)、またはサードパーティの.NET Excel互換リーダーを使用します。 SpreadsheetGear は、このようなライブラリの1つであり、適切に機能し、ExcelのCOMインターフェイスに非常によく似たインターフェイスを備えています。
他のヒント
この問題の回避策の1つは、SELECT *の代わりにselectステートメントを変更することです:
"SELECT Format([F1], 'General Number') From [Sheet1$]"
-or-
"SELECT Format([F1], \"#####\") From [Sheet1$]"
ただし、セルに255文字を超える文字が含まれている場合は、次のエラーが発生して爆発します。 "マルチステップOLE DB操作でエラーが生成されました。可能であれば、各OLE DBステータス値を確認します。作業は行われませんでした。"
幸いなことに、私の顧客はこのシナリオでエラーが発生することを気にしませんでした。
このページには、試してみたいこともたくさんあります。 http://www.dicks- blog.com/archives/2004/06/03/external-data-mixed-data-types/
この接続文字列の使用:
Provider=Microsoft.ACE.OLEDB.12.0; data source={0}; Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1\"
Excel 2010では、次のことに気付きました。 OLEDB SELECTの実行時にExcelファイルが開いている場合、保存されたファイルの値ではなく、現在のバージョンのセルが取得されます。さらに、長い数値、10進数値、および日付に対して返される文字列値は次のようになります。
5.0130370071e+012
4.08
36808
ファイルが開いていない場合、返される値は次のとおりです。
5013037007084
£4.08
Monday, October 09, 2000
Open XML SDK 2.0 Productivity Toolを使用して実際の.XSLXファイルを見ると(または単にファイルを解凍してXMLをメモ帳で表示すると)、Excel 2007は実際に生データを科学形式で保存していることがわかります。
たとえば、0.00001は1.0000000000000001E-5として保存されます
<x:c r="C18" s="11" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:v>1.0000000000000001E-5</x:v>
</x:c>
Excelでセルを見ると、セルと数式バーの両方に0.00001と表示されます。そのため、OleDBが問題を引き起こしているとは限りません。
「番号」が大きい列のテキスト形式ではなく、Zip形式を選択するのが最も簡単な方法であることがわかりました。
読みながらフィールドの値を(int)または(Int64)にキャストしようとしましたか?
GoogleでIMEX = 1接続文字列オプションとTypeGuessRowsレジストリ設定を調べます。 実際、リーダーは最初の数行(デフォルトでは8行)を見て列のデータ型を推測するため、これを簡単に回避する方法はありません。行にすべての数字が含まれている場合、運が悪いです。
過去に使用した残念な回避策は、HDR = NO接続文字列オプションを使用し、TypeGuessRowsレジストリ設定値を1に設定して、最初の行を有効なデータとして読み取ってデータ型を決定することです。 、ヘッダーではなく。 それはハックですが、動作します。コードは最初の行(ヘッダーを含む)をテキストとして読み取り、それに応じてデータ型を設定します。
レジストリの変更は苦痛ですが(常に可能とは限りません)、後で元の値に戻すことをお勧めします。
インポートデータにヘッダー行がない場合、代替オプションはファイルを前処理し、問題の列の各数字の前に '文字を挿入することです。これにより、列データがテキストとして扱われます。
全体として、これを回避するためのハックがたくさんありますが、絶対確実なものはありません。
これと同じ問題がありましたが、Excel COMインターフェイスやサードパーティソフトウェアに頼らずに回避できました。少し処理オーバーヘッドがかかりますが、私にとっては機能しているようです。
- 最初にデータを読み込んで列名を取得します
- 次に、これらの各列で新しいDataSetを作成し、各DataTypesをstringに設定します。
- この新しいデータに再度データを読み込みます データセット。 Voila-科学者 表記はなくなり、すべてが文字列として読み込まれます。
これを説明するコードをいくつか紹介します。また、追加のボーナスとして、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.
}
}
}
}
}
}
}
この状態をグーグルで検索しました。 ここに私の解任手順があります
- テンプレートExcelファイルの場合
1形式のExcelの列としてのテキスト 2-数値のエラー警告を無効にするマクロを記述します-&gt;テキスト変換
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.ErrorCheckingOptions.BackgroundChecking = Ture
End Sub
Private Sub Workbook_Open()
Application.ErrorCheckingOptions.BackgroundChecking = False
End Sub
- 分離コード
3-インポートするデータの読み取り中 Int64またはInt32。への着信データを解析しようとします...
これに対する答えが誰かにあったかどうか知りたいです。私はすべてインターウェブを行ったり来たりして、IMEXとHDRのすべての組み合わせを試しました。 IMEX = 1は、日付、通貨、および一般的な数値を抽出して管理した唯一のものです。しかし、大きな数字は依然として科学的であることが示されています。ファイルを読むだけで、スプレッドシート、レジストリを変更できます。サードパーティはオプションではありません。