【问题标题】:OLEDB custom encodingOLEDB 自定义编码
【发布时间】:2014-09-29 22:56:29
【问题描述】:

我的目标

我需要以客户指定的特定格式创建 .dbf 文件。格式为 dBase III .dbf,kamenicky 编码,使用整数、各种长度的字符和双列类型。

问题

我几乎让所有东西都正常工作,只有一个障碍:该死的编码拒绝工作,尽管编写了一个特定的转换表,它将原始字符与那些与 kamenicky 编码兼容的字符进行切换。这意味着输出文件以例如 FF 的十六进制值结束,该字符在导入的字符串中被指定为 A0 的十六进制值。

如果您要回答 (-1) 问题,我将非常感谢您提供有关您为什么在 cmets 中这样做的信息 - 即使是“您对问题的理解不够充分”也会有很大帮助,因为我会知道在哪里继续我的研究(例如,在这种情况下非常基础)

我已经解决了这个问题(见 cmets),但解决方案有缺陷,实际上根本没有回答给定的问题。

问题

如何说服 Jet.OLEDB 提供者不要乱用编码?

我尝试了什么

  • 使用 foxpro 提供程序,实际上工作正常,除了我的客户端软件无法读取生成的 .dbf 文件的小细节。

  • 在不使用 OleDbParameter 的情况下插入数据(因此输入无法正确转义)无济于事

  • 每次 A0 的输出导致 FF 时,通过 CharacterSet = xxx 和其他一些我现在不太记得的连接字符串修改设置几个不同的编码。

  • 我找到了一个 AutoTranslate 属性 over here,但据我所知,它仅适用于 SQL 连接,因为 Jet.OLEDB 不断给我一个 ISAM 错误。

  • 我曾尝试玩弄globalization settings,但没有多大帮助。

一些代码

连接字符串:

"Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0};Extended Properties=\"dBase III;\"";

然后使用 OleDbCommand 插入数据,使用 OleDbParameter 类和构造的插入字符串填充各个单元格。可能没什么用,但这里是代码:

private void insertRows(T[] data, OleDbConnection connection)
{
    using (OleDbCommand command = connection.CreateCommand())
    {
        for (int i = 0; i < data.Count(); i++)
        {
            constructParams(data[i], i, command);
            command.CommandText = constructInsert(i, _fileName);

            command.ExecuteNonQuery();
        }
    }
}

private void constructParams(T data, int index, OleDbCommand command)
{
    command.Parameters.Clear();
    foreach (PropertyInfo prop in _props)
    {
        if(_cols.ContainsKey(prop.Name))
        {
            command.Parameters.Add(new OleDbParameter("@" + prop.Name + index, prop.GetValue(data)));
        }
    }
}

private string constructInsert(int dataNum, string tableName)
{
    string insert = "INSERT INTO [" + tableName + "] (";
    foreach(string key in _cols.Keys)
    {
        insert += "[" + key + "],";
    }
    insert = insert.Remove(insert.Length - 1);
    insert += ") VALUES";

    insert += " (";
    foreach (string key in _cols.Keys)
    {
        insert += "@" + key + dataNum + ",";
    }

    insert = insert.Remove(insert.Length - 1);
    insert += ");";

    return insert;
}

【问题讨论】:

  • 我已经解决了这个问题,尽管这个解决方案远非完美。 Jet.OLEDB 使用的任何编码似乎(至少对于重要的字符)都是 8 位字符集,kamenicky 编码也是如此。因此,在 OLEDB 提供程序完成文件写入后,我以字节表示形式再次打开它并手动替换字符,以便它们遵守 kamenicky 编码。当然,这不是对原始问题的回答——只是我出于绝望而不得不求助的一个解决方案。

标签: c# .net encoding oledb


【解决方案1】:

这是我尝试过的一项快速操作,似乎正在使用特殊的 Unicode 字符,并且在您尝试使用时正确识别代码页 895。这确实使用了 Microsoft 的 VFP OleDb 提供程序。但是,我有 4 个部分。

  1. 使用显式代码页引用创建表,这通常会导致 VFP 可读格式。

  2. 要保持您提到的在 dBASE 中需要的向后兼容性,请使用 COPY TO 命令将 VFP 版本表头转换为较旧的(并且应该是)dBASE 识别格式

  3. 简单插入到表的 dBASE 版本(也是代码页 895)

  4. 检索所有记录并查看 Unicode 结果。

// Connection to your data path, but explicitly referencing codepage 895 in connection string
string connectionString = @"Provider=VFPOLEDB.1;Data Source=c:\\YourDataPath\\SomeSubFolder;CODEPAGE=895;";
string ans = "";

using (OleDbConnection connection = new OleDbConnection(connectionString))
{
   // create table syntax for a free table (not part of a database) that is codepage 895.
   string cmd = "create table MyTest1 free codepage=895 ( oneColumn c(10) )";
   OleDbCommand command = new OleDbCommand(cmd, connection);

   connection.Open();
   command.ExecuteNonQuery();

   // Now, create a script to use the MyTest1 table and create MyTest2 which 
   // SHOULD BE recognized in dBASE format.
   string vfpScript = @"use MyTest1
            Copy to MyTest2 type foxplus";


   command.CommandType = CommandType.StoredProcedure;
   command.CommandText = "ExecScript";
   command.Parameters.Add("myScript", OleDbType.Char).Value = vfpScript;
   command.ExecuteNonQuery();

   // Simple insert into the 2nd instance of the table    
   command = new OleDbCommand("insert into Mytest2 ( oneColumn ) values ( ? )", connection);
   command.Parameters.AddWithValue("parmForColumn", "çšjír_Þ‰");
   command.ExecuteNonQuery();

   // Now, get the data back.
   command = new OleDbCommand("select * from Mytest2", connection);
   OleDbDataAdapter da = new OleDbDataAdapter(command);
   DataTable oTbl = new DataTable();
   da.Fill(oTbl);

   if (oTbl.Rows.Count != 0)
      // we should have one row, so get the string from the column
      // and it SHOULD loo like the Unicode sample I inserted above.
      ans = (string)oTbl.Rows[0]["oneColumn"];
}

显然,您有代码可以循环浏览所有列并设置适用的参数,所以我将其留给您。

【讨论】:

  • 我已经在昨天的原始问题下发送了我在评论中提出的解决方案进行测试,似乎工作正常。遗憾的是,此时我没有时间正确实施/测试您的解决方案 - 如果将来有时间,我可能会回到它,我会让您知道它是否有效。无论如何,虽然未经测试,但我看不出它为什么不工作的任何理由,所以我会给你赏金/答案(至少只要它未经测试)。感谢您的努力。
猜你喜欢
  • 1970-01-01
  • 2017-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-08
  • 2021-10-30
  • 2020-06-27
  • 2020-12-04
相关资源
最近更新 更多