Cómo leer archivos planos con ADO.NET
(Antes que me la rieguen, sí, ya sé que son "archivos de texto sencillo" pero este blog está en pocho, ¿no? Digo, no hay archivos de computadora planos, o cúbicos o esféricos, que yo sepa, pero así les dicen muchos desarrolladores)
Aunque hoy en día ya todo mundo debería de estar utilizando (según yo) XML para el intercambio de información, sigue siendo muy comun que para mandar información de un sistema a otro se haga a través de archivos "planos" de texto.
Si alguna vez has lideado con sistemas legacy o en plataformas chiples (mainframe, or SAP anyone?) estoy seguro que sabes de lo que hablo. Otro caso común es cuando requieres que tu usuario genere algún archivo para cargar esos datos en tu aplicación. Harta cantidad de gerentoides y chalanes no saben ni (bleep) de sistemas o de computadoras, pero eso sí, son masters sensai del Excel, así que es fácil decirles que le den un "Save As... CSV" a un archivo para subir sus datos.
Ahora, ¿cómo le harías para leer esos archivos con .NET? Si eres entusiasta probablemente luego luego te las ingeniarías para usar un FileStream y parsear el contenido línea por línea, dar 3 maromas... qué se yo. Sin embargo, existe un truco sencillo que puede ahorrarte broncas: utilizar el OLEDB Provider de ADO.NET para hacerlo. Esta técnica funciona bastante bien para leer archivos CSV o archivos de texto con columnas en posiciones fijas (si son secuenciales, ya valiste cake).
Leyendo un archivo CSV
Por ejemplo, imagina que eres achichincle del Jason (el de las películas de terror) y te manda a hacer sus compras, de lo contrario terminarás con tu cabeza y cuerpo en diferentes sectores de la ciudad. El vato hace su "chopin list" en Excel y lo guarda en el siguiente archivo llamado jason.csv:
Producto,Cantidad,Precio
Sierra eléctrica,1,250
Máscara de hockey,1,15.50
Machete,5,2.70
Detergente para ropa (con quita-manchas),1,10
Delantal,2,7.25
Afilador,3,5
Entonces, como buen dotnetero, podrías leerlo con una rutina como esta:
// asumiendo que tenemos
// using System.Data.OleDb;
// using System.Data;
// en este connection string:
// HDR=Yes : indica que el primer registro contiene los encabezados
// (nombres) de las columnas, no datos.
// FMT=Delimited : indica que el los campos están delimitados por un caracter
// (coma por default).
string connectionString =
@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\DirectorioDeArchivosCSV;" +
"Extended Properties='text;HDR=Yes;FMT=Delimited'";
DataTable dt = new DataTable("miTabla");
using (OleDbConnection conn = new OleDbConnection(connectionString))
using (OleDbDataAdapter da = new OleDbDataAdapter("SELECT * FROM jason.csv", conn))
{
da.Fill(dt);
}
// hacer algo con los datos en el DataTable
El código es bastante sencillo, es el patrón estándar para usar un DataAdapter. Lo único de especial que tiene es que utiliza el OLEDB Data Provider, y que en el connection string le especificamos el directorio donde se encuentra el archivo, así como el formato que tiene. Nota que emites un SELECT de SQL común y corriente, por lo cual podrías agregar una cláusula WHERE si así lo quisieras.
En fin, para comprobar que en realidad funcionara el código, puse un breakpoint e invoqué el DataSet Visualizer desde Visual Studio. El resultado:
Pero, ¿qué tan inteligente es el OLEDB Provider? ¿Adivinó correctamente el tipo de mis datos?
Leyendo un archivo de texto con posiciones fijas
Ahora, asume que el méndigo Jason te la puso más difícil y en lugar de darte un archivo CSV, te da un archivo de texto sencillo como este (jason.txt):
El código sería muy similar al anterior:
// asumiendo que tenemos
// using System.Data.OleDb;
// using System.Data;
// en este connection string:
// HDR=Yes : indica que el primer registro contiene los encabezados
// (nombres) de las columnas, no datos.
// FMT=Fixed : indica que el los campos están en posiciones fijas y el tamaño
// de cada campo se especifican con un archivo SCHEMA.INI
// en el mismo directorio donde está el archivo a leer.
string connectionString =
@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\DirectorioDeArchivosTXT;" +
"Extended Properties='text;HDR=Yes;FMT=Fixed'";
DataTable dt = new DataTable("miTabla");
using (OleDbConnection conn = new OleDbConnection(connectionString))
using (OleDbDataAdapter da = new OleDbDataAdapter("SELECT * FROM jason.txt", conn))
{
da.Fill(dt);
}
// hacer algo con los datos en el DataTable
De hecho, lo único que cambió fue el parámetro FMT en el connectionString, el nombre del archivo y el directorio donde localizarlo. Sin embargo, para que esto funcione con archivos de posiciones fijas es necesario un paso adicional: especificar el tamaño (y tipo) de las columnas en el archivo.
Esto se hace mediante un archivo schema.ini que debe estar en el mismo directorio que el archivo que vas a leer. Consulta esta página para saber todas las opciones disponibles. En nuestro caso un archivo como el siguiente sería suficiente:
[jason.txt]
Format=FixedLength
Col1=Producto Char Width 40
Col2=Cantidad Long Width 10
Col3=Precio Double Width 10
Factorizando código
Si generalizamos el código un poco, podemos extraer una función sencilla que pueda ser reutilizada en varios de nuestros programas. Esa rutina podría ser como esta, en donde le pasas como parámetros el tipo y archivo a leer y te regresa un DataTable poblado ya con los datos:
// asumiendo que tenemos
// using System.Data.OleDb;
// using System.Data;
// using System.IO;
public enum TipoDeArchivoPlano { Delimited, Fixed }
public static DataTable LeerArchivoPlano(
FileInfo archivo, bool tieneEncabezado, TipoDeArchivoPlano tipoDeArchivo )
{
if (!archivo.Exists)
throw new FileNotFoundException(
"No se encontró el archivo especificado");
string conEncabezado = tieneEncabezado ? "YES" : "NO";
string connectionString = String.Format(
@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};" +
"Extended Properties='text;HDR={1};FMT={2}'",
archivo.DirectoryName, conEncabezado, tipoDeArchivo.ToString());
DataTable dt = new DataTable("miTabla");
using (OleDbConnection conn = new OleDbConnection(connectionString))
using (OleDbDataAdapter da =
new OleDbDataAdapter("SELECT * FROM " + archivo.Name, conn))
{
da.Fill(dt);
}
return dt;
}
De manera que pueda ser llamado así:
DataTable dt = LeerArchivoPlano(
new FileInfo(@"C:\DirectorioDeArchivosCSV\jason.csv"),
true, TipoDeArchivoPlano.Delimited);
En fin, la idea es esa.
Enjoy.
Actualización, 13 diciembre 2007:
Gracias a los comentarios de fredy, publiqué otro artículo con el código en Visual Basic 2005, para aquellos que les interese.



Por RSS o Atom


Me parace que el articulo de Cómo leer un archivo plano es excelente, muy útil y sencillo. Gracias
Excelente tip :)
Los ejemplos estan excelentes...
Ahora unicamente estoy batallando con el directorio que contiene el archivo csv, por que en mi compu es un path y cuando copio la aplicación al servidor es otro directorio, es que lo estoy usando en un webservice y no encuentro como obtener el app.path como lo hacia en vb6
Si quieres obtener el path donde se ejecuta tu aplicación, en una aplicación de Windows Forms, es bien sencillo, solo tienes que consultar la propiedad Application.ExecutablePath
Sin embargo, para una aplicación ASP.NET es un poco más "misterioso". Tienes que usar la clase Assembly. Algo así como:
Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location)
Buenas me parecio excelente el programa ahora tengo un problema tengo 2 archivos planos y los deseo comparar con un where estos 2 archivos tienen distinta ubicacion el problema que se me presenta es con la cadena de conexion y no se que hacer
Pues sin saber muchos de los detalles quizá esto pueda ser útil. Estoy asumiendo que ese WHERE en realidad es un JOIN (donde quieres comparar valores de un archivo contra otros). La técnica que describí era para leer un archivo a la vez. No conozco una forma en que puedas especificar en el connection string dos archivos a leer.
Lo que se me ocurre es que leas cada archivo en un DataTable separado. De esa forma tendrías, algo así como:
dt1 = LeerArchivoPlano(@"Archivo1.csv"...);
dt2 = LeerArvhivoPlano(@"Archivo2.csv"...);
Ya teniendo los datos en memoria, podrías agregar los DataTable a un DataSet y establecer una relación entre las tablas, o filtrar los datos con un DataView o usando la propiedad RowFilter, etc. Es decir ya podrías manipular tus datos por código y hacer lo que tengas que hacer.
Excelente Tip!!
Yo tengo un archivo delimitado por ";". Como hago para leerlo utilizando la misma tecnicca?
Para un archivo delimitado por ";" creo que puedes hacerlo utilizando un archivo schema.ini (de manera similar a como se hizo con el de posiciones fijas).
El contenido del archivo schema.ini sería algo como esto:
[miarchivodelimitadoporpuntoycoma.txt]
ColNameHeader=True
Format=Delimited(;)
Col1=Producto Char Width 40
Col2=Cantidad Long
Col3=Precio Double
No sé si poniendo FMT=Delimited(;) en el string de conexión también funciona.
Hola, estoy haciedno una aplicacion para leer un archivo plano y subirlo a una BDD, mi problema es que cuando leo la ruta del archivo, lee la ruta del servidor, com ohago para que lea la ruta pero del cliente que utiliza la aplicacion? de antemano muchas gracias, mi codigo es este
string fileDirectory = Path.GetDirectoryName(txtFile.PostedFile.FileName);
string fileName = txtFile.PostedFile.FileName; // Path.GetFileName(txtFile.PostedFile.FileName);
string strCommand = @"SELECT * FROM " + Path.GetFileName(txtFile.PostedFile.FileName);
string properties = @"""text;FMT=Delimited""";
string strCon = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + fileDirectory + ";Extended Properties=" + properties;
conexionXls = new OleDbConnection(strCon);
DataTable dt = new DataTable("Autos");
try
{
conexionXls.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter(strCommand, conexionXls);
adapter.Fill(dt);
// se llena el datagrid solo para ver el resultado
//Datagrid2.DataSource = dt;
//Datagrid2.DataMember = "Autos";
//Datagrid2.DataBind();
conexionXls.Close();
}
catch(Exception err)
{
Response.Write("Error : " + err.ToString());
dt = null;
}
return dt;
quise utilizar como lo indicas mas arriba con Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location)
y el resultado es algo como esto
@"c:\windows\microsoft.net\framework\v1.1.4322\temporary asp.net files\pruebaajax\e12f2105\10aa5fe7\assembly\dl2\678e2b31\8f5fe85f_63cac701"
sabes que pueda estar pasando?
gracias
Hugo:
Parece que lo que intentas hacer es leer un archivo que el usuario va a subir a tu sitio ¿Te estoy entendiendo bien?
Si es ese el caso entonce puedes hacerlo mediante un control FileUpload. Tú determinas la ruta a donde se guarda ese archivo en el servidor (de donde podrás leerlo).
Por ejemplo, puedes tener lo siguiente en tu página aspx:
<asp:FileUpload id="miFileUpload" runat="server" />
<asp:Button ID="botonSubir" runat="server" Text="Subir Archivo" OnClick="SubirArchivo" />
Y luego agregar el siguiente manejador para el evento en el code-behind:
protected void SubirArchivo(object sender, EventArgs e)
{
if (miFileUpload.HasFile)
{
miFileUpload.SaveAs(@"C:\larutaenmiserver\" + miFileUpload.FileName);
// código para leer el contenido archivo va aquí...
}
}
Asegúrate solamente que el usuario ASPNET tenga permisos de escritura sobre el directorio a donde quieres subir los archivos.
Espero te sirva.
que tal kamikaze:
muchas gracias por tu ayuda, la verdad mi intencion era leer un archivo desde la ruta del cliente, pero lo que hice con el codigo que me expusiste fué, subir el archivo a mi servidor, y desde ahi leerlo, ya una ves que lo leí y lo almacene en mi base de datos, elimino el archivo para que no me genere espacio en el servidor
muchas gracias por tu ayuda
Excelente! Me gustaria saber cómo utilizar este mismo programa con archivos de texto o csv grandes de aprox. 200MB?
No conozco de ninguna restricción en cuanto a tamaño, más que la memoria de tu máquina. A final de cuentas lo estás metiendo en un DataTable vulgar, común y corriente.
¿Has tenido algún problema en específico?
Como logro leer un archivo .csv sin usar OleDB?
Excelente interpretacìón, hasta un novato podría implementarlo.
Un saludo
Disculpa tengo un problema con respecto a que el oledb no me adivino correctamente los datos tengo una columna donde tengo mas numeros que alfanumericos y me puso solamente los numericos y se esta comiendo los de texto no sabes que puedo hacer para moverle al tipo de dato que recibo o a que le muevo para que me reciba los de texto
Creo que la forma en que funciona el adaptador OleDB, para determinar los tipos de dato, es que intenta inferirlos de acuerdo al primer registro de datos. Así que si para una columna tienes renglones con números y luego renglones con letras creo que toma el primero para determinar el tipo de dato (en este caso números). Todos los renglones que no cumplen con los el tipo de dato son ignorados (en este caso los renglones con letras).
Sin embargo, siempre puedes hacer "override" de los tipos de dato que infiere y especificar los correctos utilizando un archivo schema.ini, como lo muestra la sección de "Leyendo un archivo de texto con posiciones fijas".
Espero te sirva.
Respecto a cómo leer un archivo plano sin usar esta técnica... yo lo he hecho con un FileStream común y corriente, pero luego tienes que leer línea por línea y "parsearla" (dividir los valores de acuerdo a las comas), poner los valores de cada renglón en una colección o en un data table, etcétera).
Esto parece no tener mucho chiste dado que podrías usar String.Split() para hacerlo, pero luego te metes en broncas de "¿qué pasa si los valores de una de mis columnas son strings y contienen una coma como parte del valor?" y cosas divertidas como esas.
El adaptador OleDB ya trae lógica para lidear con esas situaciones decentemente.
En fin, igual y en un artículo futuro me aviento cómo hacer esto. Si les interesa, háganmelo saber.
Buenas,
Creo que mi problema va a ser de veriones (Frwk 2.0 VS 2005) por que utilizo la forma delimitada y el problema que tengo es que solo lee una columna. Tengo
Hola amigos yo estoy iniciando en Visiual B6, tengo un problema yo quiero leer un archivo plano, pero este esta delimitado por comas, (por eso no hay problema, a lavez los campos estan entre comillas dobles asi: "BYCO1","NOE","07/10/2007" como hacer para que los saque de la cadena y los coloque es variables diferentes
Me parece muy interesante este articulo.
Quisiera saber como puedo escribir la info que poseo en un gridview y llevarlo a un archivo plano.
mil gracias.
El articulo esta super.... pero ahora tengo una siguiente duda yo debo procesar muchos archivos con la misma estructura pero con nombre diferente, como le puedo hacer??
Noe--
Supongo que estás intentando leer la info en Visual Basic ".NET". La neta ya ni me acuerdo cómo se hacía en VB6.
Una vez que tus datos ya están en el DataTable, ese objeto te va a dar acceso a una colección de rows, y cada row tendrá una columna por cada columna leída del archivo. De ahí puedes extraer los datos y ponerlos en variables distintas, si así lo quisieras. Es mucho rollo para explicar en un comentario, así que te recomiendo otro de los artículos de este sitio: ADO.NET para novatos
Anónimo (1)--
¿Estás hablando de un GridView de Windows o de ASP.NET? Pregunto porque se "bindean" a fuentes distintas en WinForms y en WebForms. Por ejemplo, en WebForms, típicamente le das un SqlDataSource (usando la propiedad DataSourceID) o un DataSet/DataTable (usando las propiedades DataSource y DataMember). En el caso del SqlDataSource es un poco más difícil "exportar" los datos, ya que solo tienes acceso los comandos configurados. Lo que puedes hacer es pasar el SelectCommand a un DataReader, p.ej. y de ahí hacer una rutina que lea los datos y escriba al archivo .CSV. En el caso de un DataSet/DataTable, pues ya tienes los datos ahí, solo necesitas iterar por la colección de rows de la tabla que te interese y escribir el archivo como te guste.
Anónimo (2)--
Si tus archivos no necesitan un schema.ini, entonces lo único "difícil" es obtener la lista de archivos, iterar por ella y pasarle cada archivo al método LeerArchivoPlano(). Esto es bien sencillo, y se puede lograr con las propiedades de la clase Directory o DirectoryInfo de System.IO. Roberto Galindo tiene un buen post sobre esto en su blog. Ahora que si tus archivos sí requiren de un schema.ini, entonces la cosa se complica un poquitito más; lo que yo he hecho en el pasado es copiar cada archivo y renombrarlo para que tenga el nombre del archivo especificado en el schema.ini, leerlo, luego borrar el archivo, copiar el siguiente y ponerle nombre, leer ese, borrarlo, etcétera. Todo esto no es tan complicado, las clases File y FileInfo (también de System.IO) te ayudan con todo eso.
Hola,
Exelente trabajo, estaba buscando justamente esto, pero me surge un gran problema.
Al igual que un anónimo anterior, me da error en la carga de datos. Si lo hago con csv solamente me despliega una columna incluyendo el encabezado como datos.
P.e.:
NOMBRE,SALARIO,IR
Mirna Reyes,
Gloria Solorzano,
etc,etc,etc
Si lo hago con txt me aparecen las 3 columnas, supongo que porque el archivo ini está bien, pero me aparecen las celdas vacías.
Revisé los archivos con notepad y aparentemente están bien estructurados y todo eso.
Gracias de antemano
piyey--
Pudiera ser que se comporte así si no especificas los valores para las tres columnas (al menos en el primer renglón de datos).
¿Has intentado con algo así?
NOMBRE,SALARIO,IR
Mirna Reyes,10,loquesea
Gloria Solorzano,0,otrovalor
O (acabo de pensar en esto), si los valores para salario e IR deben ser vacíos, solo necesitarías las puras comas:
NOMBRE,SALARIO,IR
Mirna Reyes,,
Gloria Solorzano,,
Espero te sirva.
Para leer en secuencia varios archivos con la misma extensión (VB.NET 2003) tienes que:
1. Crear un manejador de la info del directorio y ubicar el directorio:
Dim infoDir As New DirectoryInfo(directorio)
2. Crear un manejador para los archivos en ese manejadro de directorio
Dim infoFiles As FileInfo() = infoDir.GetFiles()
3. Crear un manejador para la info de cada archivo
Dim filesInfo As FileInfo
4. Procesar cada uno de los archivos recuperando nombres, extensiones, tamaños, o lo que quieras
For Each j In infoFiles
sSql = "SELECT * FROM " & j.Name
If j.Length > 0 Then
CsvTable = New DataTable
CsvAdapter = New OleDbDataAdapter(sSql, CxCsv)
CsvAdapter.Fill(CsvTable)
CsvDataset.Tables.Add(CsvTable)
End If
Next
Hola kamikaze, y gracias por la respuesta. Pero el problema es que el archivo csv si contiene los datos, de hecho probé con tu mismo ejemplo, y lo que yo puse por acá es lo que se muestra en el grid... ahora me aparece todos los datos pero en una sola columna... esto es:
P.e.:
Fila1,Fila2,Fila3
valor1,valor2,valor3
ovalor1,ovalor2,ovalor3
...
Todo eso en una sola columna...
Creo que voy a tener que hacerlo con alguna rutina que lea el archivo excel o algún copy en el portapapeles porque ya no se que hacer y en mi trabajo me estan ·$%&/( jejeje
Saludos y gracias
hola como esta me a surgido un problema similar en mi caso es como pasar un archivo con otro tipo que no es txt sino de tipo LIS ademas quisiera saber si hay una manera de pasar automaticamente con un click los datos a mi BD y tambien Como exportar mis tablas de la BD a formato de texto plano con esta regla
si el campo nombre es de 10 y solo e colocado el nombre salvador el resto de campos se tendria que llenar con espacios en blanco en el archivo de texto plano
ejemplo
campo longitud
nom 8
ape 10
si nom=juan y ape=garcia al momento de exportar en el texto tedria que ser asi
juanbbbbgarciabbbb
donde b es espacio en blanco, necesito si ayuda por favor
Me temo que no estoy familiarizado con los archivos .LIS, así que no creo poderte ayudar con eso. Pero si son basado en texto y son delimitados por algún caracter o por posiciones como describe este artículo, no rebes tener problemas.
Ahora, eso de subir tus datos a tu base de datos no es automático, pero no requirere mucho esfuerzo. La rutina que se mostró en este artículo pone tus datos en un DataTable, el cual podrías utilizar con un DataSet y un DataAdapter para ejecutar las instrucciones necesarias de inserción en tu base de datos. Échale un ojo a este otro artículo para más detalles: ADO.NET para novatos.
Ahora, para escribir los datos de tu BD a un archivo, típicamente sería a la inversa, es decir, llenarías un DataTable o DataSet a partir de tu base de datos y de ahí es sencillo hacer un ciclo que los vaya leyendo registro por registro y escribiendo los valores a un archivo. Típicamente utilizarías un FileStream o StreamWriter para hacerlo. Roberto Galindo Venzor tiene una descripción breve en su blog .
Para agregar los valores en blanco cuando estás escribiendo los valores al archivo, puedes utilizar el método PadRight() de la clase string. P.ej. suponiendo que tienes una variable miVar de tipo string, podrías hacer myVar.PadRight(10," ") que indica "regresa el valor de mi variable con un ancho máximo de 10 caracteres y rellénalo con espacios hacia la derecha".
Espero te ayude.
Hola, he probado el código este para llenar el DataTable y me lanza el siguiente error:
"El motor de base de datos Microsoft Jet no pudo encontrar el objeto 'test3_07.11.06_14.21.00.csv'. Asegúrese de que el objeto existe, y que ha escrito el nombre y la ruta de acceso al objeto correctamente."
Lo hago desde Visual Basic en ASP.NET 2, he comprobado la ruta y es correcta. Te pongo el código que uso:
Public Shared Function LeerArchivoPlano(ByVal archivo As FileInfo, _
ByVal tieneEncabezado As Boolean, _
ByVal tipoDeArchivo As TipoDeArchivoPlano) As DataTable
If (Not archivo.Exists) Then
Throw New FileNotFoundException("No se encontró el archivo especificado")
End If
Dim conEncabezado As String = IIf(tieneEncabezado, "YES", "NO")
Dim connectionString As String = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};" + "Extended Properties='text;HDR={1};FMT={2}'", archivo.DirectoryName, conEncabezado, tipoDeArchivo.ToString())
Dim dt As DataTable = New DataTable("ww")
Using conn As OleDbConnection = New OleDbConnection(connectionString)
'Using da As OleDbDataAdapter = New OleDbDataAdapter("SELECT * FROM " + Path.GetFileNameWithoutExtension(archivo.FullName), conn)
Using da As OleDbDataAdapter = New OleDbDataAdapter("SELECT * FROM " + archivo.Name, conn)
da.Fill(dt)
End Using
End Using
Return dt
End Function
Qué tal Fredy,
Tu código se ve bien (muy buena "traducción", por cierto).
¿Ya verificaste que el usuario ASPNET tenga permisos de seguridad sobre el directorio donde están los archivos que quieres leer? Normalmente si el directorio es distinto a donde corre la aplicación ASP.NET, por seguridad, no tendrá permisos ni de leer los archivos. Chécalo y me dices si no para ver qué más pudiera ser.
Hola Carlos, las pruebas las he hecho en local. La carpeta donde estan los .csv estan dentro (en una subcarpeta) de la aplicación. No tendría que tener problemas de permiso ya que es en local y hago otro proceso (en el mismo directorio) que descomprime un archivo y copia los archivos en otra carpeta.
No se si puede afectar que aunque trabaje en local, tenga la conexion de SqlServer apuntando al servidor remoto, no tiene porque afectar no?
Gracias.
Me hiciste volver a hacer el ejemplo en Visual Basic, canijo. ;-)
Pues creo que ya establecimos que no es bronca de código. Si no le estuvieras pasando bien el archivo a la rutina te estaría arrojando el error de "no se encontró el archivo especificado", no el error acerca del motor de datos jet (creo yo).
Así que es tiempo de revisar la configuración de tu máquina. Igual y te falta algún driver o algo así.
Lo que hay que hacer es ir a Control Panel > Administrative Tools > Data Sources (ODBC), pestaña de drivers (aquí hay una imagen de cómo aparece en mi máquina).
Yo tengo listado varios drivers de texto:
Driver da Microsoft para arquivos texto (*.txt, *.csv) v4.x...
Microsoft Access Text Driver (*.txt, *.csv) v12.x....
y Microsoft Text Driver (*.txt, *.csv) v4.
Estoy casi seguro que el de Access es inconsecuente. Y el que está en portugués no sé ni que rollo, pero igual y te sirve para comparar con tu máquina.
Espero te sirva.
Oh, y no, no creo que tu conexión a SQL Server tenga nada que ver tampoco.
Hola, resulta al final que el problema era el nombre del archivo, ya que contenia puntos en el nombre, una vez sin puntos ya no da error.
Ahora el problema es que me devuelve una sola columna y con los primeros datos solo (los de tipo int), a partir del primer campo de tipo string ya no los devuelve.
Estoy usando asp .net 2.
Que láaaaaaaaaaaastima!! con lo bonito que parecía llegar a ser.
Sabes como arreglar esto?
Gracias.
Órale, esa no me la sabía (lo de los puntos en el nombre del archivo). Normalmente, por seguridad (y muchas veces para facilitar las cosas) renombro los archivos que recibo de los usuarios, así que nunca había tenido ese problema.
Las broncas de que no te traiga correctamente los datos (especialmente cuando contienen muchas columnas) las he visto porque las columnas de texto contienen comas como parte de los datos. Lo mismo se hacen pelotas el Excel o Access (ambos usan el mismo driver de OleDb que el ejemplo del artículo, detrás de las cámaras). En este caso lo que debes asegurarte es que las columnas de texto estén delimitado por comillas.
Agregar un schema.ini también ayuda mucho a asegurar que se lea el tipo de dato correcto por cada columna.
Espero te ayude
Estuve trabajando el ejercicio tal cual el unico problema es que los datos del archivo plano o csv quedan impresos solo en una columna.
Si alguien sabe el porque le agradesco su retroalimentacion.
El ejercicio esta bien solo que me muestra todos los datos del archivo plano en una sola columna, asi el archivo tenga varias columnas, si alguien sabe por que .....
Para los que están teniendo el problema de que sus datos aparecen en una sola columna:
Parece que Diego ya le atinó con algunas cosas para resolverlo. Yo le hice el comentario que si tienes campos tipo fecha a veces son latosos (porque en "español" y en "inglés" se leen distinto, p.ej. 05/06/2008 es 6 de mayo en EE.UU. pero es 5 de junio en países hispanos). En fin, les copio aquí su mensaje:
"Carlos Cordial Saludo. Escribo para decir que ya pude llenar el dataset completamente con columnas y todo, gracias a tus consejos me puse a indagar profundamente en archivos txt, csv, y schemas.ini. En síntesis mi problema era con el idioma de mi sistema operativo , las comillas me sirvieron en muchos campos pero implicaba hacer un trabajo extra pero el ( ; ) sirvió perfectamente .Me tope con un excelente articulo el cual me llevo por otros caminos en cuanto al trabajar con archivos de este tipo y me encontré con muchas características tales como se ven en este articulo:
http://www.mvp-access.es/softjaen/articulos/texto/jet_text_isam.htm#Index21
De pronto hace una simbiosis perfecta con tu articulo y puede ayudar a mucha gente que tiene mi problema de pronto si quieres hacer un síntesis y complementar tu gran articulo que me sirvió bastante para realizar mi aplicación.
De Nuevo Gracias por la atención y la ayuda .
Diego Fernando Bernal B.
Desde Colombia."
PD. También pudiera serles útil la página de referencia sobre schema.ini en MSDN (parece que cambió desde que escribí el artículo)
Espero les ayude
cel ejemplo es muy bueno pero como le hago para llamarlo en un aplicacion de escritorio, llenar un grid con un boton alguin sabe porfavor gracias
Como la rutina regresa un DataTable, debe ser sencillo. Creo que solo necesitas ponerlo como la propiedad DataSource de tu grid.
Y si deseas levantar filas filtradas? como harias?
Ejemplo.. "SELECT * FROM " & archivo.name & " WHERE condicion 1"
Se podria realizar algo de ese estilo?
Gracias.
Debes de poder hacerlo. Como lo menciona el artículo, es una sentencia de SQL común y corriente. No estoy seguro de GROUP BY's y cosas así pero si es un simple filtro WHERE columna=valor debes poder hacerlo. Quizá necesites utilizar un archivo schema.ini para que sepas de antemano el nombre de las columnas, pero aparte de eso no veo ningún impedimento.
Saludos, quiero colaborar con una solución que me funcionó para la separación de los datos y evitar que todos se carguen en la misma columna, es algo muy simple pero sólo de esta forma logré solucionarlo, el truco está en declarar las columnas antes que el delimitador, siguiendo el ejemplo posteado sería así por ejemplo
[jason.txt]
Col1=Producto Char Width 40
Col2=Cantidad Long Width 10
Col3=Precio Double Width 10
Format=Delimited(;)
Con esto tna sencillo logré separar los datos, si a alguno ha probado las soluciones anteriores y no le ha funcionado como a mi, podría probar este pequeño cambio a ver si mejora la suerte.
Tu articulo me parecio excelente. Fue una gran ayudaaa
Felicitaciones desde Lima, Peru
Agradecera que me pudieran ayudar con lo siguiente:
Tengo que hacer una aplicacion que me lea un archivo de texto delimitado(",") y subir esos datos a un datagrid; pero como son bastantes datos dentro del archivo de texto y estan por parrafos con informacion repetida quisiera seleccionar de cada parrafo algunos datos para que el datagrid los visualice en la primera fila y que del siguiente parrafo yo pueda seleccionar ls mismos datos y visualizarlos en la 2da fila y asi sucesivamente hasta llegar al final del archivo.
Gracias