【问题标题】:Create .DBF file from SQL table records从 SQL 表记录创建 .DBF 文件
【发布时间】:2015-12-11 05:56:36
【问题描述】:

我想从 SQL 表记录创建一个.DBF 文件。

比如SQL中有一个名为CountryMaster的表,它有5列:

  1. ID int identity(1,1)
  2. 名称 varchar(100)
  3. 详细信息 varchar(200)
  4. 状态位
  5. CreatedDate 日期时间

它有 100 行。

如何从 C# 中导出带有 .DBF 文件中标头的这些记录?

注意:创建的.DBF 文件大小必须非常紧凑。

【问题讨论】:

  • 我想这可能会回答你的问题stackoverflow.com/questions/322792/…
  • 这适用于哪个 RDBMS?请添加标签以指定您使用的是mysqlpostgresqlsql-serveroracle 还是db2 - 或其他完全不同的东西。
  • 所以您想导出数据从 SQL Server 到 dBase、Clipper 或 Foxpro 文件(哪一个)?您根本不需要为此使用 C#,您是否尝试过集成服务或 SSMS 中的导出数据向导?该向导实际上创建了一个 SSIS 包,您可以对其进行编辑以满足您的需要。如果需要,您甚至可以在 C# 代码中使用相同的提供程序、连接字符串
  • @PanagiotisKanavos 删除了答案,因为它正在使用工具。OP 可以按照github.com/SocialExplorer/FastDBF/blob/master/TestDbfLib/…的示例
  • @marc_s 你对他的 NOTE 有何看法:dbf 文件大小必须非常紧凑。

标签: c# .net dbf


【解决方案1】:

您可以看到Xbase Data file (*.dbf) 结构并编写自己的代码,但我已经完成了实现并且已经使用了多年。在这里你可以在GitHub找到它


如何使用库

在名为 DbfFile.cs 的文件中有一些 write 方法。您可以使用其中任何一个。我将解释其中的一些:

第一种写法

DataTable另存为dbf文件:

static void Write(string fileName, System.Data.DataTable table, Encoding encoding)
  • fileName: 是您希望保存.dbf 输出文件的位置。
  • table: 是您从 SQL Server 或任何其他来源读取的数据。
  • encoding: 保存字符串数据时使用的编码

第二种写法

List<T> 保存到 dbf 文件中。

static void Write<T>(string fileName,
                                    List<T> values,
                                    List<Func<T, object>> mapping,
                                    List<DbfFieldDescriptor> columns,
                                    Encoding encoding)

读取数据库并将结果保存到某个类类型中,然后使用此方法将类值保存到 dbf 文件中。下面是它的参数说明:

  • fileName:要保存的dbf文件名
  • values:您的数据作为 T 类型的对象列表保存到 dbf 文件中
  • mapping:告诉此方法如何从类类型中检索数据的函数列表。
  • columns:dbf列信息
  • encoding:dbf文件的编码。

第二种写入方法示例

由于第一种方法很简单,我为您提供了第二种写入方法的示例。考虑您要将List&lt;MyClass&gt; 数据保存到dbf 文件中。这是代码

class MyClass
{
    public int Id {get;set;}
    public string Name {get;set;}
}

现在您可以像这样将List&lt;MyClass&gt; 保存到 dbf 文件中:

var idColumn = DbfFieldDescriptors.GetIntegerField("Id");
var nameColumn = DbfFieldDescriptors.GetStringField("Name");
var columns = new List<DbfFieldDescriptor>() { idColumn, nameColumn };

Func<MyClass, object> mapId = myClass => myClass.Id;
Func<MyClass, object> mapName = myClass => myClass.Name;
var mapping = new List<Func<MyClass, object>>() { mapId, mapName };

List<MyClass> values = new List<MyClass>();
values.Add(new MyClass() { Id = 1, Name = "name1" });

DbfFileFormat.Write(@"C:\yourFile.dbf", values, mapping, columns, Encoding.ASCII);

同样使用这个库你可以读取 dbf 文件并且你的代码不能 取决于Microsoft.Jet.OLEDB 或其他任何东西。

好好享受吧。

【讨论】:

  • 我在第一种方法中遇到错误“命名空间 'IRI.Ket' 中不存在类型或命名空间名称 'IO'(您是否缺少程序集引用?)”
  • @Chirag 我更新了 GitHub 源代码。如果您有任何其他问题,请告诉我
  • 我不会投反对票,但当出现此类错误时,我肯定会犹豫是否使用未知程序员的随机 GitHub 库。
  • 是的。我已经将其更改为 200 并解决了错误,但文件大小为 54 MB(太大)。如果我想将它减少到 10 MB 以下,你会说什么?
  • 无论如何,如果您正在寻找可以减少 dbf 文件大小的答案(但从技术上讲,它对给定数据集没有意义),请考虑编辑您的问题并在您的问题中提及这一点。无论如何,我建议您寻找其他格式并忘记 .dbf 格式。
【解决方案2】:

您需要的大部分信息都可以在Trouble with Insert Into .dbf file 中看到,因为它展示了如何在创建 .dbf 文件时创建表并将值插入其中。您需要对已指定的字段进行一些修改,但该页面描述了您需要的所有内容。

【讨论】:

  • 谁投了我的票:我提供的信息和 OP 一样多。 OP 甚至没有展示他们尝试过的任何工作。用勺子喂食的请求最好通过使请求者能够更多地思考、交流和参与的方向来回答。
  • 我没有投反对票,但正如您所见,答案已被编辑,似乎他正在寻找一个完全不同的问题,所以如果您能提供帮助并相信什么,您可能想编辑您的答案他想要的(用给定的数据集压缩一个 dbf 文件!)可以实现。
  • @Chirag,我还添加了将结果导出为 CSV 文件的功能,它会自动修剪数据并包含列标题。
【解决方案3】:

我想帮忙。但是,我还是坚持使用 OLEDB for VPF 的简单流程。

创建表 DBF

这可能是您为 .DBF 创建表的脚本

CREATE TABLE "C:\test.dbf" ([ID] Numeric(18,0), [Name] Char(100) NULL, [Details] Char(200) NULL, [Status] Logical NULL, [CreateDate] DATETIME NULL)

然后,您可以从 OLE DB 脚本中调用它,如下所示。

    string vpfScript = "CREATE TABLE \"C:\test.dbf\" ([ID] Numeric(18,0), [Name] Char(100) NULL, [Details] Char(200) NULL, [Status] Logical NULL, [CreateDate] DATETIME NULL)";
    string connectionString = @"Provider=VFPOLEDB.1;Data Source=C:\test.dbf";
    OleDbConnection connection = new OleDbConnection(connectionString);

    using (OleDbCommand scriptCommand = connection.CreateCommand())
    {
         connection.Open();
         scriptCommand.CommandType = CommandType.StoredProcedure;
         scriptCommand.CommandText = "ExecScript";
         scriptCommand.Parameters.Add("myScript", OleDbType.Char).Value = vfpScript;
         scriptCommand.ExecuteNonQuery();
    }

在表格中导入行

要在 DBF 表中导入行,它不像我们在其他 DB 中执行的常用 SQL 脚本。

    string vpfScript = "INSERT INTO \"C:\test.dbf\" ([ID], [Name], [Details], [Status], [CreateDate]) VALUES (1,'test john','test details',.t.,{^2015-09-15)";
    string connectionString = @"Provider=VFPOLEDB.1;Data Source=C:\test.dbf";
    OleDbConnection connection = new OleDbConnection(connectionString);

    using (OleDbCommand scriptCommand = connection.CreateCommand())
    {
        connection.Open();
        scriptCommand.CommandType = CommandType.StoredProcedure;
        scriptCommand.CommandText = "ExecScript";
        scriptCommand.Parameters.Add("myScript", OleDbType.Char).Value = vfpScript;
        scriptCommand.ExecuteNonQuery();
    }

您现在可以更改适合您需要的值,就像下面的用法一样。

    DataTable dt = new DataTable(); // assuming this is already populated from your SQL Database.
    StringBuilder buildInsert = new StringBuilder();
    string connectionString = @"Provider=VFPOLEDB.1;Data Source=C:\test.dbf";
    OleDbConnection connection = new OleDbConnection(connectionString);

    using (OleDbCommand scriptCommand = connection.CreateCommand())
    {
         connection.Open();

         foreach(DataRow dr in dt.Rows)
         {
             string id = dr["ID"].ToString();
             string name = dr["Name"].ToString();
             string details = dr["Details"].ToString();
             string status = Convert.ToBoolean(dr["Status"]) ? ".t." : ".f.";
             string createDate = "{^" + Convert.ToDateTime(dr["CreateDate"]).ToString("yyyy-MM-dd") + "}";
             builderInsert.Append("INSERT INTO \"C:\test.dbf\" ([ID], [Name], [Details], [Status], [CreateDate]) VALUES (" + id + ",\"" + name + "\",\"" + details + "\"," + status + "," + createDate + ")" + Environment.NewLine);

             scriptCommand.CommandType = CommandType.StoredProcedure;
             scriptCommand.CommandText = "ExecScript";
             scriptCommand.Parameters.Add("myScript", OleDbType.Char).Value = builderInsert;
             scriptCommand.ExecuteNonQuery();
             builderInsert = "";
          }
     }

如果您还有其他问题,请告诉我。 不要忘记在你的机器上安装这个。 VFP OLE DB

【讨论】:

  • 虽然您使用 VFP OleDB 是出于好意,但您也遇到了问题(包括 SQL 注入)。连接字符串应始终指向 PATH,而不是显式表。由此,当您发出 CREATE TABLE 或 INSERT INTO 时,您只需要指定表名,它将应用于指定的 PATH 中的表。您可能没有读/写/修改权限,尤其是在您的示例所具有的根 C:\ 级别。它可以工作,但需要调整,还需要从 SQL-Server 中提取对象,然后插入到 VFP 表中。
  • 我同意安全要点。我在这里的目的只是帮助用户从任何数据库导出到 .dbf,假设用户不知道 FoxPro 脚本的 OLE-DB 使用情况。这甚至可以通过 SSIS 或 DTS 2000 实现最简单的导出形式,但我宁愿通过 C# 进一步解释事情,而不是拖放设置。感谢您的宝贵时间!
【解决方案4】:

为了为您提供 C# 解决方案,我首先下载Microsoft Visual Foxpro OleDb Provider,它适用于 .DBF 表。

在 C# 代码的顶部,添加

using System.Data.SqlClient;
using System.Data.OleDb;

然后,在一个方法内移动数据

    void MoveFromSQLToDBF()
    {    
        // have a table to pull down your SQL Data...
        var dataFromSQL = new DataTable();

        // However your connection to your SQL-Server
        using (var sqlConn = new  SqlConnection("YourSQLConnectionString"))
        {
           using (var sqlCmd = new SqlCommand("", sqlConn))
           {
              // Get all records from your table
              sqlCmd.CommandText = "select * from CountryMaster";
              sqlConn.Open();
              var sqlDA = new SqlDataAdapter();
              // populate into a temp C# table
              sqlDA.Fill(dataFromSQL);
              sqlConn.Close();
           }
        }

        // Now, create a connection to VFP 
        // connect to a PATH where you want the data.
        using (var vfpConn = new OleDbConnection(@"Provider=VFPOLEDB.1;Data Source=C:\SomePathOnYourMachine\"))
        {
           using (var vfpCmd = new OleDbCommand("", vfpConn))
           {
              // Create table command for VFP
              vfpCmd.CommandText = "CREATE TABLE testFromSQL ( ID Numeric(18,0), [Name] Char(100) NULL, [Details] Char(200) NULL, [Status] Logical NULL, [CreateDate] DATETIME NULL)";

              vfpConn.Open();
              vfpCmd.ExecuteNonQuery();

              // Now, change the command to a SQL-Insert command, but PARAMETERIZE IT.
              // "?" is a place-holder for the data
              vfpCmd.CommandText = "insert into testFromSQL "
                 + "( ID, [Name], [Details], [Status], [CreateDate]) values ( ?, ?, ?, ?, ? )";

              // Parameters added in order of the INSERT command above.. 
              // SAMPLE values just to establish a basis of the column types
              vfpCmd.Parameters.Add( new OleDbParameter( "parmID", 10000000 ));
              vfpCmd.Parameters.Add( new OleDbParameter( "parmName", "sample string" ));
              vfpCmd.Parameters.Add(new OleDbParameter( "parmDetails", "sample string" ));
              vfpCmd.Parameters.Add(new OleDbParameter( "parmStatus", "sample string" ));
              vfpCmd.Parameters.Add( new OleDbParameter( "parmCreateDate", DateTime.Now ));

              // Now, for each row in the ORIGINAL SQL table, apply the insert to VFP
              foreach (DataRow dr in dataFromSQL.Rows)
              {
                 // set the parameters based on whatever current record is
                 vfpCmd.Parameters[0].Value = dr["ID"];
                 vfpCmd.Parameters[1].Value = dr["Name"];
                 vfpCmd.Parameters[2].Value = dr["Details"];
                 vfpCmd.Parameters[3].Value = dr["Status"];
                 vfpCmd.Parameters[4].Value = dr["CreateDate"];
                 // execute it
                 vfpCmd.ExecuteNonQuery();
              }

              // Finally, for compactness, use a VFP Script to copy to Excel (CSV) format
              using (var vfpCmd2 = new OleDbCommand("", vfpConn))
              {
                 vfpCmd2.CommandType = CommandType.StoredProcedure;
                 vfpCmd2.CommandText = "ExecScript";

                 vfpCmd2.Parameters.Add(new OleDbParameter( "csvScript", 
@"Use testFromSQL
copy to YourCompactFile.csv type csv
use" ));

                 vfpCmd2.ExecuteNonQuery();
              }

              // close VFP connection
              vfpConn.Close();

           }
        }
    }

由于OleDb不支持复制TYPE CSV,我为你找到了this post on S/O to dump into CSV format

【讨论】:

  • 他不只是在寻找从 SQL 到 dbf 的数据传输。他虽然有可能拥有紧凑的 dbf 文件,所以他也在寻找它!
  • @HosseinNarimaniRad,这将完全创建一个简单、紧凑的 .DBF 独立文件,其中包含从 SQL 查询的那些记录。至于紧凑,获取 CSV 文件将与您获得的一样紧凑(修剪)。
  • 我同意你的观点,并且已经建议他忘记 dbf 文件,但他认为可以通过给定的记录和列数以及对列大小的一些限制来减小 dbf 文件的大小(但是我告诉他根据 dbf 规范这是不可能的)。有关更多解释,您可以查看我的回答下面的 cmets。
  • @kenlacoste,是的,但是参数化、提取数据并转储为紧凑的 CSV 格式。 .DBF 并不是真正需要的,可能只是转储为 CSV 原始文件,但不知道它们的整体实施需求。
  • 先生,我使用了您上面的代码。我收到错误消息,即在使用您的代码以实现紧凑性时功能不可用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-30
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
相关资源
最近更新 更多