Está en la página 1de 12

Acceso a ficheros dBase

(.dbf) desde Visual Basic


.NET y C#
Autor: Guillermo 'guille' Som

Los ficheros de dBase (extensión .dbf) son ficheros de bases de datos usados por lenguajes
de programación xBase como dBase, Clipper y [Visual] FoxPro, aquí te explico cómo usarlas
desde Visual Basic .NET y C# usando ADO.NET.

La batallita del agüelo:

Nota:
Si no quieres tragarte todo este rollo, puedes ir directamente a la explicación
y al código de ejemplo.

Por si te preguntas que hace el Guille a estas alturas de la vida explicando cómo
acceder a ficheros del tipo dBase, los que tienen la extensión .dbf, (que sin que nadie
se moleste, son de una tecnología más vieja que yo), decirte que la verdad es que
NUNCA he necesitado acceder a ese tipo de ficheros de bases de datos... hasta hace
un par de días...

Fíjate si nunca los he usado que lo que tengo en mi sitio sobre cómo acceder a los
ficheros dBase desde Visual Basic 6.0 (o anterior) está escrito por colaboradores, y
fue algo que publiqué por primera vez en Noviembre de 1998 (¡hace más de 10
años!).

Como te digo nunca he necesitado saber cómo acceder a este tipo de bases de datos
(las de extensión .dbf), pero el otro día, un colega de aquí de Nerja, que está usando
un programa que hice en MS-DOS hace ya más de 20 años (aunque lo sigo
manteniendo) y me dijo que necesitaba que le pasara datos con formato de la
exportación de ContaPlus a mi programa.
Cuando he tratado con este tipo de exportaciones, siempre he preferido el formato
ASCII, o sea, en texto de longitud fija, pero resulta que esos datos que quería
importar en mi programa los había exportado a su vez de un programa de hotel y
resulta que la gente esa del programa de hotel (que por cierto le han cobrado una
pasta gansa por el programa y además tienen un contrato mensual de mantenimiento
de 60 euros mensuales), pasan olímpicamente de este colega y solo hacen darle
largas... y como resulta que el formato de exportación del programa de hotel (para
compatibilizar con ContaPlus) es del tipo XBASE, es decir, en ficheros con la extensión
.dbf, que para más señas son del tipo usado por Visual FoxPro (ahora te cuento
porqué hago esta aclaración), pues... tuve la necesidad de "aprender" a usarlos para
así poder leer la información y guardarla en el formato que usa mi programa.

¿Y qué hace uno cuando necesita saber algo de programación? (aparte de entrar en el
sitio del Guille)
Pues eso, buscar en los buscadores de Internet (en mi caso, sólo usé Google, pa que
te voy a decir otra cosa).
¿Y qué fue lo que me encontré?
Pues... aparte de algún que otro link a lo que tengo en mi sitio para VB6 o anterior,
algunas cosas más... pero casi todos los ejemplos usaban cadenas de conexión para
dBase IV o dBase III y los que había para usar con FoxPro, pues... no me
funcionaban, además probando de dos formas, es decir, con los proveedores para
usar con objetos del tipo OleDb u Odbc.

Cuando usaba los drivers para dBase, tanto desde OleDb como desde Odbc, el error
que me daba era:
External table is not in the expected format,
que traducido (casi libremente) viene a decir: La tabla externa no está en el formato
esperado
(en el mensaje de Odbc añadía ERROR [HY000] y cuatro cosas más, pero en el fondo
el error era el mismo).

Decirte que las bases de datos .DBF en realidad son tablas, es decir, cada fichero es
una tabla. Te digo esto, porque al principio tampoco tenía ni idea de cómo acceder a
la tabla (con la cadena SELECT), pero después me di cuenta de que había que poner
en mismo nombre del fichero (con o sin la extensión, eso no influye), ya que en la
cadena de conexión, lo que hay que indicar es el directorio en el que están las "tablas"
a las que queremos acceder.

Aclarado esto, te voy a mostrar el código (para Visual Basic .NET) que usé para
acceder a las bases de datos usando OleDb y Odbc (recuerda que esto solo es válido
para bases de datos del tipo dBase).

Comentar que sBase es una variable de tipo String en la que está el nombre completo
de uno de los ficheros .dbf a los que quiero acceder, por eso se extrae el directorio a
la hora de crear la cadena de conexión. Por otro lado, la variable sConn es una
variable de tipo String.

Usando objetos de System.Data.OleDb:

sConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _


System.IO.Path.GetDirectoryName(sBase) & _
";Extended Properties=dBASE IV;"

Using dbConn As New System.Data.OleDb.OleDbConnection(sConn)


Usando objetos de System.Data.Odbc:

sConn = "Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=" & _


System.IO.Path.GetDirectoryName(sBase) & ";"

Using dbConn As New System.Data.Odbc.OdbcConnection(sConn)

Recuerda que estas dos formas solamente funcionan con bases de datos más
antiguas, es decir, las creadas con dBase (y puede que con Clipper, pero no te lo
puedo asegurar). Es decir, NO serviría para abrir bases de datos creadas con FoxPro
(o compatibles con el formato usado por ese lenguaje).

Sigo con mi batallita.

La cuestión es que los ficheros de prueba que yo tenía no los abría con esas cadenas
de conexión y probando con otras específicas de FoxPro, tampoco, ya que me decía
que no tenía nada que hacer...

Si probaba OleDb con la cadena:


Provider=vfpoledb.1;Data Source=<el directorio>
El error era: The 'vfpoledb.1' provider is not registered on the local machine, que
traducido sería algo así como que el proveedor ese no está registrado en la máquina
local (también probé con vfpoledb).

Si probaba con Odbc usando la cadena (que finalmente es la correcta):


Driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=<el
directorio>
El error era: Driver does not support this function, que traducido sería algo así como:
El driver no soporta esta función.

El código de OleDb lo probé mucho después que el del Odbc, ya que si me llega a dar
un error como ese de OleDb, en el que se indica "claramente" que el proveedor usado
no está registrado, me hubiera dado cuenta de que me faltaba algo en mi equipo para
que esto funcionara, ya que el error ese de que el driver no soporta la función, lo que
me viene a decir, es que el driver SÍ está presente, pero que alguno de los
parámetros está mal.
En las pruebas que hice la cadena de conexión tenía más opciones que después me he
dado cuenta que no son necesarias, al menos si se quieren usar los valores
predeterminados, ya que la cadena de conexión era algo así:
"Driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=" &
System.IO.Path.GetDirectoryName(sBase) & ";Exclusive=No;
Collate=Machine;NULL=NO;DELETED=NO;BACKGROUNDFETCH=NO;"

Y como en mi búsqueda me topé con programas que abrían esos tipos de ficheros e
incluso me permitían exportarlos a otros formatos, y algunos de ellos los abrían todos,
lo que pensé es que el Guille es más torpe de la cuenta y no es capaz de abrir un
fichero de tipo .DBF.
Pero no soy tan torpe, ya que finalmente conseguí lo que me proponía (bueno, en
realidad, algo torpe si que soy, pero no demasiado, al menos eso es lo que puedo
aparentar, particularmente después de haber dado con la clave de mis quebraderos
de cabeza con los dichosos ficheros .dbf).

La cuestión es que uno de estos programas te permitían exportar los datos a formato
dBase IV, dBase III, FoxPro, etc. Así que, los exporté. Y pude abrir (usando el código
de OleDb) los que tenían formato dBase, pero no los de FosPro ni los que tenía
originales.

Y como soy muy morruo (además de torpe), pensé que si ese programa (y otros dos
más que probé) son capaces de abrir ese tipo de ficheros... pues... eso, que ¿por qué
yo no iba a ser capaz?

La cosa es que me busqué la estructura de este tipo de ficheros, lo abrí con un editor
de texto (en modo binario y normal a ver si...) y lo único que saqué en claro es lo que
después vi en la página de explicación del formato .dbf y en la que explica los
formatos según el primer byte del fichero, que para el fichero con formato dBase III
era 03, para dBase IV era 43 y para FoxPro era 30 (todo en hexadecimal).
Y como resulta que los ficheros que yo tenía también tenían un 30, fue fácil deducir
que estaban en formato de Visual FoxPro, por tanto... tenía que usar las cadenas de
conexión de FoxPro, pero... si no me funcionaban... (recuerda que me daba error de
que el driver no soportaba la función) ¿qué hacer?

Pues... lo que tendría que haber hecho unas cuantas horas antes: ir al sitio de
Microsoft y bajarme los drivers para Visual FoxPro (si es que es de cajón, pero... en
fin...).

Y eso hice, busqué dónde estaban esos drivers, los bajé, los instalé y todo
funcionando, además, con esa cadena de conexión me permitía abrir los tres tipos de
ficheros .dbf... en fin...

Usa este link si necesitas descargar los drivers ODBC de Microsoft Visual FoxPro para
abrir cualquier tipo de ficheros .dbf (al menos los compatibles) y con toda seguridad,
algunos más (los usados por ese lenguaje).

Y este otro link es para descargar los drivers OLEDB de Microsoft Visual FoxPro
9.0 (aunque este ni lo he bajado, ni por supuesto, lo he instalado ni probado).

Y ahora te explicaré algo del formato .dbf y te mostraré el código para abrir y acceder
a bases de datos que están en estos tipos de ficheros (usando ODBC), y como dice el
título de este artículo, usando Visual Basic .NET y Visual C#.

Explicación del formato usado por el tipo .dbf y


ejemplos
Si no quieres saber "un poco" de cómo es el formato de los ficheros .dbf puedes pasar
directamente al código de cómo acceder a los ficheros .dbf usando ODBC (por
supuesto con código para Visual Basic .NET y para el de Visual C#).

Explicación (rápida) de qué es un fichero de tipo .dbf

Sin enrollarme demasiado, comentarte que un fichero .dbf (al menos los compatibles
con el original de dBase o los usados por los lenguajes conocidos
como xBase: dBase, Clipper, FoxPro / Visual Fox Pro, etc.) en realidad es el
equivalente a una tabla de una base de datos. Ese fichero incluye la información de
los campos que tiene esa tabla, de qué tipos son, cuántos registros hay y cuáles son
esos registros (si es que hay alguno).

Nota de los cuelgues del Expression Web 2:


Al ir a añadir el link del texto de abajo, se me colgó y como ese texto lo escribí y no
guardé antes de ir a poner el link, pues... lo perdí... en fin... por suerte, se cuelga
menos que antes...

Y otra vez se ha colgado, esta vez, al poner los links del párrafo de arriba... en fin...
tendré que reiniciar el equipo a ver si... ¡zeñó, zeñó, que crú con el e-precion güé!

Si quieres saber más sobre la estructura de los ficheros xBase (extensión .dbf),
puedes verlo desde este link:
Estructura de los ficheros .dbf.

El código de ejemplo usando el controlador ODBC


Como el título dice, vamos a usar las clases del espacio de nombres
System.Data.Odbc para acceder a los ficheros con extensión .dbf, que tal como te he
comentado antes, lo que contienen es una tabla.

Para crear el ejemplo, tendrás que crear una aplicación de Windows, añadir dos cajas
de texto, dos botones y un DataGridView (todo esto si tienes el Visual Studio 2005 o
superior).

Una de las cajas de texto (txtFic) tendrá el path a un fichero con la extensión .dbf
(admite drag & drop), de lo que haya en esa caja de textos se usará solo el nombre
del directorio.
La otra caja de texto (txtSelect) tendrá el nombre del fichero al que queremos
acceder, y tal como ya te he comentado, ese nombre de fichero en realidad lo
usaremos como nombre de la tabla. Y tal como he comentado antes, se puede indicar
tanto con la extensión .dbf como sin ella. En las operaciones de abrir o arrastrar y
soltar se toma el nombre del fichero soltado (o abierto) sin la extensión y es lo que se
asigna en esa caja de textos.
Los botones sirven para seleccionar un fichero (btnExaminar) y el otro para abrir la
tabla (btnAbrir) y mostrarla en el grid (dgvDiarios).

Este es el código de Visual Basic para abrir la "base de datos"


(más abajo tienes el código completo de VB del formulario):

Dim sBase As String = txtFic.Text


Dim sSelect As String = "SELECT * FROM " & txtSelect.Text
Dim sConn As String

sConn = "Driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=" & _


System.IO.Path.GetDirectoryName(sBase) & ";"

Using dbConn As New System.Data.Odbc.OdbcConnection(sConn)


Try
dbConn.Open()

Dim da As New System.Data.Odbc.OdbcDataAdapter(sSelect, dbConn)


Dim dt As New DataTable

da.Fill(dt)

dgvDiarios.DataSource = dt

dbConn.Close()

Catch ex As Exception
MessageBox.Show("Error al abrir la base de datos" & vbCrLf &
ex.Message)
Exit Sub
End Try
End Using

Este es el código de Visual C# para abrir la "base de datos"


(más abajo tienes el código completo de C# del formulario):

string sBase = txtFic.Text;


string sSelect = "SELECT * FROM " + txtSelect.Text;
string sConn;
sConn = "Driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=" +
System.IO.Path.GetDirectoryName(sBase) + ";";

using (System.Data.Odbc.OdbcConnection dbConn = new


System.Data.Odbc.OdbcConnection(sConn))
{
try
{
dbConn.Open();

System.Data.Odbc.OdbcDataAdapter da = new
System.Data.Odbc.OdbcDataAdapter(sSelect, dbConn);
DataTable dt = new DataTable();

da.Fill(dt);

dgvDiarios.DataSource = dt;

dbConn.Close();

}
catch (Exception ex)
{
MessageBox.Show("Error al abrir la base de datos\n" + ex.Message);
return;
}
}

Y esto es todo... solo comentarte que te fijes en la cadena SELECT, en la que se indica
el nombre del fichero al que queremos acceder (y en la cadena de conexión hay que
indicar el directorio en el que está ese fichero), y que puede estar con o sin la
extensión .dbf.

Espero que te sea de utilidad.

Nos vemos.
Guillermo

Resto del código del formulario de prueba

El código del formulario para Visual Basic .NET:


Imports System
Imports System.Windows.Forms
Imports System.Data

Public Class Form1

Private Sub btnExaminar_Click(ByVal sender As Object, _


ByVal e As EventArgs) _
Handles btnExaminar.Click
Dim oFD As New OpenFileDialog
With oFD
.Filter = "Ficheros DBF (*.dbf)|*.dbf|Todos (*.*)|*.*"
.FileName = txtFic.Text
If .ShowDialog = DialogResult.OK Then
txtFic.Text = .FileName
' El nombre del fichero
txtSelect.Text =
System.IO.Path.GetFileNameWithoutExtension(txtFic.Text)
btnAbrir_Click(Nothing, Nothing)
End If
End With
End Sub

Private Sub btnAbrir_Click(ByVal sender As Object, _


ByVal e As EventArgs) _
Handles btnAbrir.Click
Dim sBase As String = txtFic.Text
Dim sSelect As String = "SELECT * FROM " & txtSelect.Text
Dim sConn As String

sConn = "Driver={Microsoft Visual FoxPro


Driver};SourceType=DBF;SourceDB=" & _
System.IO.Path.GetDirectoryName(sBase) & ";"

Using dbConn As New System.Data.Odbc.OdbcConnection(sConn)


Try
dbConn.Open()

Dim da As New System.Data.Odbc.OdbcDataAdapter(sSelect, dbConn)


Dim dt As New DataTable
da.Fill(dt)

dgvDiarios.DataSource = dt

dbConn.Close()

Catch ex As Exception
MessageBox.Show("Error al abrir la base de datos" & vbCrLf &
ex.Message)
Exit Sub
End Try
End Using

End Sub

Private Sub Form1_DragDrop(ByVal sender As Object, _


ByVal e As DragEventArgs) _
Handles Me.DragDrop, txtFic.DragDrop
' Drag & Drop, aceptar el primer fichero
If e.Data.GetDataPresent("FileDrop") Then
txtFic.Text = CType(e.Data.GetData("FileDrop", True), String())(0)
txtSelect.Text =
System.IO.Path.GetFileNameWithoutExtension(txtFic.Text)
End If
End Sub

Private Sub Form1_DragEnter(ByVal sender As Object, _


ByVal e As DragEventArgs) _
Handles Me.DragEnter, txtFic.DragEnter
' Drag & Drop, comprobar con DataFormats
If e.Data.GetDataPresent(DataFormats.FileDrop) Then
e.Effect = DragDropEffects.Copy
End If
End Sub
End Class

El código del formulario para C#:


public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_DragEnter(object sender, DragEventArgs e)


{
// Drag & Drop, comprobar con DataFormats
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
}

private void Form1_DragDrop(object sender, DragEventArgs e)


{
// Drag & Drop, aceptar el primer fichero
if (e.Data.GetDataPresent("FileDrop"))
{
txtFic.Text = ((String[])e.Data.GetData("FileDrop", true))[0];
txtSelect.Text =
System.IO.Path.GetFileNameWithoutExtension(txtFic.Text);
}
}

private void btnExaminar_Click(object sender, EventArgs e)


{
OpenFileDialog oFD = new OpenFileDialog();
oFD.Filter = "Ficheros DBF (*.dbf)|*.dbf|Todos (*.*)|*.*";
oFD.FileName = txtFic.Text;
if (oFD.ShowDialog() == DialogResult.OK)
{
txtFic.Text = oFD.FileName;
// El nombre del fichero
txtSelect.Text =
System.IO.Path.GetFileNameWithoutExtension(txtFic.Text);
btnAbrir_Click(null, null);
}
}

private void btnAbrir_Click(object sender, EventArgs e)


{
string sBase = txtFic.Text;
string sSelect = "SELECT * FROM " + txtSelect.Text;
string sConn;

sConn = "Driver={Microsoft Visual FoxPro


Driver};SourceType=DBF;SourceDB=" +
System.IO.Path.GetDirectoryName(sBase) + ";";

using (System.Data.Odbc.OdbcConnection dbConn = new


System.Data.Odbc.OdbcConnection(sConn))
{
try
{
dbConn.Open();

System.Data.Odbc.OdbcDataAdapter da = new
System.Data.Odbc.OdbcDataAdapter(sSelect, dbConn);
DataTable dt = new DataTable();

da.Fill(dt);

dgvDiarios.DataSource = dt;

dbConn.Close();

}
catch (Exception ex)
{
MessageBox.Show("Error al abrir la base de datos\n" +
ex.Message);
return;
}
}
}
}
Glosario:
Morruo: Tozudo, obstinado, cabezón, en el sentido de cabezota que cuando se le
mete algo en la cabeza no hay quién lo convenza de otra cosa.

Espacios de nombres usados en el código de este


artículo:
System.Data
System.Data.Odbc
System.IO