2010-10-02 69 views
0

J'utilise C# et .NET 3.5, en essayant d'importer des données à partir de vieux fichiers dbf en utilisant ODBC avec Microsoft dBase Driver.Problèmes d'encodage avec les fichiers dBase III .dbf sur différentes machines

Les fichiers dbf sont au format dBase III et utilisent le codage ibm850 pour les chaînes. Maintenant, quand j'exécute mon programme sur ma machine, toutes les données de chaîne lues par OdbcDataReader sont converties en UTF-16 ou UTF-8 ou quelque chose, idk et je l'enregistre en UTF-8 et tout va bien, mais lorsque j'essaie d'utiliser ce programme sur une boîte XP, certains caractères ne sont pas convertis correctement en UTF-8. 'Õ' par exemple. Il y en a peut-être d'autres aussi. Des caractères comme 'Ä', 'Ö' et 'Ü' sont acceptables. C'est le problème. Peut-être que l'ODBC ou le pilote utilise des informations de culture de machine ou quelque chose pour tout gâcher.

Est-il possible de lire les chaînes de la base de données en tant que binaires? Peut-être que certaines fonctions comme CONVERT ou CAST? Ou où pourrais-je trouver quelques références pour les fonctions SQL et la syntaxe qui fonctionne pour ce pilote dBase ou d'autres pilotes? J'ai cherché autour et je n'ai rien trouvé. Je me sens si aveugle en utilisant ODBC et SQL.

En ce moment j'utilise un hack temporaire qui remplace tous les σ avec Õ.

Merci!

code Exemple:

System.Data.Odbc.OdbcConnection oConn = new System.Data.Odbc.OdbcConnection(); 
oConn.ConnectionString = @"Driver={Microsoft dBase Driver (*.dbf)};DriverID=277;Dbq=" + dbPath + ";"; 
oConn.Open(); 

System.Data.Odbc.OdbcCommand oCmd = oConn.CreateCommand(); 
oCmd.CommandText = @"SELECT name FROM " + dbPath + "TABLE.DBF"; 

System.Data.Odbc.OdbcDataReader reader = oCmd.ExecuteReader(); 
reader.Read(); 

byte[] buf = Encoding.UTF8.GetBytes(reader.GetString(0)); 
BinaryWriter writer = new BinaryWriter(File.Open(@"C:\DBF\Test.txt", FileMode.Create)); 
writer.Write(buf); 

Résultat:

E5 dans DBF (Õ 850)

Test.txt sur pc1: C3 95 (O en UTF-8)

Test.txt sur pc2: CF 83 (σ en UTF-8)

Répondre

2

Si vous rencontrez toujours un problème avec ces fichiers, il se peut que je puisse vous aider. Qu'est-ce que dans le "octet de page de code" aka "ID de pilote de langue" (LDID) au décalage 29 (décimal) dans le fichier? J'ai un lecteur DBF basé sur Python qui peut lire à peu près n'importe quel type de données de champs et à peu près n'importe quelle page de codes - il a une longue liste compilée à partir de diverses sources de mappages de page de codes. Les options sont (1) croire le LDID, livrer Unicode (2) ignorer le LDID, livrer des octets non codés (3) remplacer le LDID, décoder avec une page de code spécifique en Unicode. L'Unicode peut bien sûr être encodé en UTF-8. Le lecteur DBF fait également beaucoup de vérifications croisées raisonnables qui peuvent aider à déterminer pourquoi VFP pense que le fichier est corrompu.

Comment savez-vous qu'il utilise IBM850? Une autre partie du code Python que j'ai est un détecteur d'encodage prototype, qui contrairement aux détecteurs comme 'chardet' qui sont dérivés du code de Mozilla n'est pas centré sur le web et peut heureusement reconnaître les vieilles pages de code DOS.

Une observation: la lettre grecque sigma minuscule (σ) est 0xE5 dans la page de code 437, qui a été remplacée par la page de codes 850 - "pc2" semble un peu désuet ...

Si vous pensez que je peux être d'une quelconque aide, ne hésitez pas à me envoyer un courriel à insert_punctuation (« sjmachin », « lexique », « net »)

+0

Salut im également avoir un problème avec la lecture d'un fichier Dbase, fonctionne très bien lors de la lecture sur mon client Windows suédois mais bouscule les caractères lorsqu'il est exécuté sur un OS anglais, offrez-vous toujours une assistance? – Andreas

+0

@Andreas: écrivez-moi. Quel est le LDID du fichier? Que lisez-vous avec? "bouscule les caractères" n'aide pas. Afficher repr (caractères attendus), repr (caractères réels). Si possible, envoyez-moi votre code et votre fichier. –

+0

Je vous ai envoyé un e-mail sjmachin à lexique dot net – Andreas

0

Avez-vous essayé d'utiliser le pilote Visual Foxpro "V FPOleDb "pilote au lieu ???

+0

Oui, je l'ai. Pilote Foxpro n'a pas aimé ma base de données - me dit qu'il est corrompu, mais tout semblait bien quand j'ai ouvert le fichier dans un éditeur hexadécimal et l'a comparé aux spécifications de format de fichier. – Ivarpoiss

1

Essayez ce code.

var oConn = new System.Data.Odbc.OdbcConnection(); 
oConn.ConnectionString = "Driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=" + dbPath; 
oConn.Open(); 
var oCmd = oConn.CreateCommand(); 
oCmd.CommandText = @"SELECT name FROM " + dbPath + "TABLE.DBF"; 
var reader = oCmd.ExecuteReader(); 
reader.Read(); 
byte[] A = Encoding.GetEncoding(Encoding.Default.CodePage).GetBytes(reader.GetString(0)); 
string p = Encoding.Unicode.GetString((Encoding.Convert(Encoding.GetEncoding(850), Encoding.Unicode, A))); 
1

Lorsque vous lisez le fichier DBF vous devez comprendre que vous devez prendre en compte 3 types d'encodage:

1.Encoding dans lequel le fournisseur de base de données lit le fichier. Cela dépend du fournisseur et du système d'exploitation actuel. Ce codage doit être utilisé pour la réception de tableaux d'octets. Par exemple sur mon PC:

  • lorsque j'utilise la chaîne de connexion « Data Source = {0}; Provider = Microsoft.JET.OLEDB.4.0; Propriétés étendues = DBase IV utilisateur ID =; Mot de passe = ; "les chaînes sont lues en utilisant 866 page de code (russe MS-DOS)

  • lorsque j'utilise la chaîne de connexion" source de données = {0}; Provider = vfpoledb.1; exclusif = Non, Collating séquence = machine ", les chaînes sont lues en utilisant Encoding.Default (1251 code page)

2.Encodage dans lequel les chaînes sont écrites dans le fichier dbf. Il peut être reçu à partir de 29 octets de fichier dbf, mais en fait il n'y a pas de quoi que ce soit comment le codage de fichiers dbf est marqué, vous devriez juste savoir quel encodage a été utilisé. Ce codage doit être utilisé comme codage source lors de la conversion de chaîne

3.Encodage auquel chaîne doit être convertie. C'est UTF-8 habituellement.

donc la conversion de chaîne devrait ressembler à ceci:

byte[] bytes = Encoding.GetEncoding(codePage1).GetBytes(reader.GetString(0)); 

string result = Encoding.UTF8.GetString((Encoding.Convert(Encoding.GetEncoding(codePage2), Encoding.UTF8, bytes)));