2009-01-09 24 views
6

Tengo un trabajo C#/.Net que importa datos de Excel y luego los procesa. Nuestro cliente entrega los archivos y los procesamos (importante porque no tengo ningún control sobre el archivo original).Notación científica al importar desde Excel en .Net

Uso la biblioteca OleDb para llenar un conjunto de datos (odio escribir ese código. En serio, ¿hay algún código que un desarrollador .Net teme escribiendo más que eso?). El archivo contiene algunos números como 30829300, 30071500, etc. El tipo de datos para esas columnas es "Texto".

Esos números se convierten a notación científica cuando importo los datos. ¿Hay alguna forma de evitar que esto suceda?

-Chris

+0

¿Qué datos estás importando el cadena de números en? – scottm

Respuesta

3

La biblioteca OleDb será, la mayoría de las veces, daña tus datos en una hoja de cálculo de Excel. Esto se debe en gran medida a que obliga a todo a un diseño de columna de tipo fijo, adivinando en el tipo de cada columna de los valores en las primeras 8 celdas de cada columna. Si adivina mal, terminas con cadenas de dígitos convertidas a notación científica. ¡Blech!

Para evitar esto, es mejor que te saltes el OleDb y leas la hoja directamente. Puede hacerlo utilizando la interfaz COM de Excel (¡también blech!) O un lector compatible con .NET Excel de terceros. SpreadsheetGear es una de esas bibliotecas que funciona razonablemente bien, y tiene una interfaz que es muy similar a la interfaz COM de Excel.

0

he encontrado que la manera más fácil es elegir formato Zip, en lugar de formato de texto para las columnas con los números '' grandes.

+0

Como dije antes, no tengo control sobre el archivo. El cliente crea eso. – ChrisDiRulli

0

¿Ha intentado convertir el valor del campo en (int) o quizás (Int64) mientras lo está leyendo?

+0

No "leo" el archivo, la API de OleDb lo hace. Simplemente invoco el método "fill" en el OleDbDataAdapter y paso un DataSet. El Dataset se llena con jugosos y deliciosos datos. – ChrisDiRulli

+0

¿El conjunto de datos está fuertemente tipado para que ese campo espere un número? – palehorse

+0

No, no está fuertemente tipado. – ChrisDiRulli

0

Busque la opción de cadena de conexión IMEX = 1 y la configuración de registro TypeGuessRows en google. En verdad, no hay una manera fácil de evitar esto porque el lector infiere los tipos de datos de columna mirando las primeras filas (8 por defecto). Si las filas contienen todos los números, no tiene suerte.

Una solución desafortunada que he utilizado en el pasado es utilizar la opción de cadena de conexión HDR = NO y establecer el valor de configuración de registro TypeGuessRows en 1, lo que obliga a leer la primera fila como datos válidos para hacer su tipo de datos determinación, en lugar de un encabezado. Es un truco, pero funciona. El código lee la primera fila (que contiene el encabezado) como texto, y luego establece el tipo de datos en consecuencia.

Cambiar el registro es un problema (y no siempre es posible) pero recomiendo restaurar el valor original después.

Si sus datos de importación no tienen una fila de encabezado, entonces una opción alternativa es preprocesar el archivo e insertar un 'carácter antes de cada uno de los números en la columna infractora. Esto hace que los datos de columna se traten como texto.

Así que en general, hay muchos hacks para evitar esto, pero nada realmente infalible.

+0

probé la propiedad IMEX = 1 ... la cadena de caracteres es "Provider = Microsoft.ACE.OLEDB.12.0; Data Source = # FILEPATH #; Extended Properties = 'Excel 12.0 Xml; HDR = NO; IMEX = 1" pero el valor viene como 2,13123219999999E + 18 ........... – dankyy1

+0

Debe establecer también la entrada de registro TypeGuessRows. Como dije, es un hack desafortunado. –

0

Tuve este mismo problema, pero pude evitarlo sin recurrir a la interfaz COM de Excel o software de terceros. Implica un poco de procesamiento, pero parece estar funcionando para mí.

  1. Primera lectura de los datos para obtener los nombres de las columnas
  2. A continuación, crear un nuevo conjunto de datos con cada una de estas columnas, el establecimiento de cada una de sus DataTypes a cadena.
  3. Lea de nuevo los datos en este nuevo conjunto de datos . Voila: la notación científica ya no está y todo se lee como una cadena.

Aquí hay un código que ilustra esto, y como una ventaja adicional, ¡es incluso 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. 
         } 
        } 
       } 
      } 
     } 
    } 
} 
+0

cansé este bloque de código pero todavía valoré en sc.notación ... – dankyy1

+0

¡maldita sea! ¿este tipo de problema no te hace querer arrancarte el pelo? –

0

I Googled alrededor de este estado .. Aquí están mis pasos solulition

  • Para plantilla de Excel archivo

1-formato Excel como texto de Coloumn macro 2- escritura para inhabilitar advertencias de error para Número -> conversión de texto

Private Sub Workbook_BeforeClose(Cancel As Boolean) 
Application.ErrorCheckingOptions.BackgroundChecking = Ture 
End Sub 
Private Sub Workbook_Open() 
Application.ErrorCheckingOptions.BackgroundChecking = False 
End Sub 
  • El código subyacente

3- durante la lectura de los datos a importar intenta analizar los datos entrantes a Int64 o Int32 ....

0

estoy interesado en saber si alguien tiene una respuesta a esta . He estado subiendo y bajando por los interwebs e intenté todas las combinaciones de IMEX y HDR. IMEX = 1 es el único con el que logré extraer los valores de fecha, moneda y número general. Pero los grandes números aún se muestran como científicos. Solo necesito leer archivos y cambiar hojas de cálculo, registro, terceros no es una opción.

5

Una solución a este problema es cambiar su instrucción de selección, en lugar de SELECT * hacer esto:

"SELECT Format([F1], 'General Number') From [Sheet1$]" 
-or- 
"SELECT Format([F1], \"#####\") From [Sheet1$]" 

Sin embargo, al hacerlo, hacer estallar si sus células contienen más de 255 caracteres con el siguiente error: "La operación OLE DB de varios pasos generó errores. Compruebe cada valor de estado de OLE DB, si está disponible. No se realizó ningún trabajo".

Afortunadamente, a mi cliente no le importaba el error en este escenario.

Esta página tiene un montón de cosas buenas para tratar así: http://www.dicks-blog.com/archives/2004/06/03/external-data-mixed-data-types/

+0

Oye. Usé esta solución y parecía arreglar las cosas para mí. El problema es que parece redondear cada número para que los últimos dos dígitos sean ceros. Por ejemplo, 12345678 se convierte en 12345600. ¿Alguien sabe cómo arreglaría esto? – Loogawa

1

Si nos fijamos en el archivo .xslx real utilizando SDK de XML abierto herramienta de productividad 2.0 (o simplemente descomprima el archivo y ver el XML en Bloc de notas) verá que Excel 2007 en realidad almacena los datos sin procesar en formato científico.

Por ejemplo 0,00001 se almacena como 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> 

En cuanto a la célula en Excel su muestra como 0,00001 tanto en la célula y la barra de fórmulas. Por lo tanto, no siempre es cierto que OleDB está causando el problema.

2

El uso de esta cadena de conexión:

Provider=Microsoft.ACE.OLEDB.12.0; data source={0}; Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1\" 

con Excel 2010 me he dado cuenta lo siguiente. Si el archivo de Excel está abierto cuando ejecuta OLEDB SELECT, obtendrá la versión actual de las celdas, no los valores guardados del archivo. Por otra parte los valores de cadena devueltos para un número largo, valor decimal y el aspecto fecha de la siguiente manera:

5.0130370071e+012 
4.08 
36808 

Si el archivo no está abierto entonces los valores devueltos son:

tipo
5013037007084 
£4.08 
Monday, October 09, 2000 
Cuestiones relacionadas