el Guille, la Web del Visual Basic, C#, .NET y más...

Acceso a ficheros dBase (.dbf) desde Visual Basic .NET y C#

 
Publicado el 07/Feb/2009
Actualizado el 07/Feb/2009
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 



 


La fecha/hora en el servidor es: 22/11/2024 20:11:46

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024