2

我有几个需要能够查询的第三方生成的 DBF 文件。我遇到了麻烦,因为所有列类型都被定义为字符,但其中一些字段中的数据实际上包含二进制数据。如果我尝试使用 OleDbDataReader 将这些字段作为字符串或字符数组以外的任何内容读取,我会抛出 InvalidCastException,但我需要能够将它们作为二进制值读取,或者至少在读取它们之后进行转换/转换. 实际包含文本的列按预期返回。

例如,第一列定义为长度为 2 个字节的字符字段,但该字段包含一个 16 位整数。

我编写了以下测试代码来读取第一列并将其转换为适当的数据类型,但值不正确。

数据库的第一行在第一列中的值为 17365 (0x43D5)。运行以下代码,我最终得到的是 17215 (0x433F)。我很确定这与使用 ASCII 编码从数据读取器返回的字符串中获取字节有关,但我不确定将值转换为我需要的格式的另一种方法,除此之外编写我自己的 DBF 阅读器并完全绕过 ADO.NET,除非我绝对必须这样做,否则我不想这样做。任何帮助将不胜感激。

        byte[] c0;
        int i0; 

        string con = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\ASTM;Extended Properties=dBASE III;User ID=Admin;Password=;";

        using (OleDbConnection c = new OleDbConnection(con))
        {
            c.Open();
            OleDbCommand cmd = c.CreateCommand();
            cmd.CommandText = "SELECT * FROM astm2007";
            OleDbDataReader dr = cmd.ExecuteReader();
            while (dr.Read())
            {
                c0 = Encoding.ASCII.GetBytes(dr.GetValue(0).ToString());

                i0 = BitConverter.ToInt16(c0, 0);
            }
            dr.Dispose();
        }
4

2 回答 2

0

您可能遇到的实际上是基于备忘录的字段...这些列实际上在另一个文件中具有原始文本(通常是 .DBT (dBASE) 或 .FPT (FoxPro)。它是文本中的指针偏移量内容文件,长度自由,分块写入,但指针存储在 4 个字节中。

如果您可以访问 .dbf 查看器并且可以在某种程度上本地查看它,那可能会对您有所帮助。

于 2010-05-18T17:17:02.643 回答
0

我很确定您对 ASCII 字符转换是正确的。我查找了 Jet 引擎支持的标量函数,但找不到它们……或者更确切地说,我发现列出了标量函数但没有语法。该CONVERT功能可能是您想要的。就像是:

SELECT CONVERT(twobytefield, SQL_BINARY) from astm2007

然后你可以打电话dr.GetBytes()来读取原始数据。但是,我无法使用 Jet 引擎喜欢的函数构造语句。

如果您无法进行转换,另一种可能性是使用Advantage .NET Data Provider。或 OLE DB 提供程序(但 .NET 数据提供程序可能更适合,因为您使用的是 C#)。该提供程序读取 DBF 文件并支持 CONVERT 标量函数。它有一个免费的本地引擎。

既然您提到您将尝试它并且因为我对其进行了测试以确保我没有撒谎,所以这是我使用的代码片段:

AdsConnection conn = new AdsConnection( 
   @"data source=c:\path;chartype=ansi;ServerType=local;TableType=cdx;" );
conn.Open();
AdsCommand cmd = conn.CreateCommand();
cmd.CommandText = "select cast(somefield as sql_binary) from sometable";
cmd.CommandType = CommandType.Text;
AdsExtendedReader rdr = cmd.ExecuteExtendedReader();
rdr.Read();
byte[] c0 = rdr.GetBytes( 0 );
int i0 = BitConverter.ToInt16( c0, 0 );
Console.WriteLine( "val = {0}", i0 );
于 2010-05-18T18:02:22.943 回答