web-dev-qa-db-fra.com

SSIS - Fichier plat toujours ANSI jamais codé UTF-8

Avoir un package SSIS assez simple:

  • Source OLE DB pour obtenir des données via une vue (toutes les colonnes de chaîne dans la table de base de données nvarchar ou nchar).
  • Colonne dérivée pour formater la date existante et l'ajouter à l'ensemble de données (type de données DT_WSTR).
  • Tâche de multidiffusion pour diviser le jeu de données entre:
    • OLE DB Commande pour mettre à jour les lignes comme "traitées". 
    • Destination du fichier à plat - le gestionnaire de connexion est défini sur Code Page 65001 UTF-8 et Unicode est décochée. Toutes les colonnes de chaîne sont mappées sur DT_WSTR.

Chaque fois que je lance ce paquet, ouvrez le fichier à plat dans Notepad ++, son ANSI, jamais UTF-8. Si je coche l'option Unicode, le fichier est UCS-2 Little Endian.

Est-ce que je fais quelque chose de mal? Comment puis-je obtenir que le fichier plat soit encodé en UTF-8?

Merci

14
Neil

OK - semblait avoir trouvé une solution de contournement acceptable sur Forums SQL Server . Je devais essentiellement créer deux fichiers de modèle UTF-8, utiliser une tâche de fichier pour les copier vers ma destination, puis vérifier que j'y ajoutais des données plutôt que de les écraser.

0
Neil

Dans Source -> Éditeur avancé -> Propriétés du composant -> Définissez la page de code par défaut sur 65001 AlwaysUseDefaultCodePage sur True.

Puis Source-> Editeur avancé -> Propriétés d’entrée et de sortie Cochez chaque colonne des colonnes externes et des colonnes OutPut et définissez CodePage sur 65001 dans la mesure du possible.

C'est tout.

En passant, Excel ne peut pas définir de données UTF-8 dans le fichier. Excel est simplement un gestionnaire de fichiers. Vous pouvez également créer des fichiers csv en utilisant le bloc-notes. tant que vous remplissez le fichier csv avec UTF-8, ça devrait aller.

22
Mirav Rathod

Ajout d'explication aux réponses ...

si vous définissez CodePage sur 65001 (mais ne cochez PAS la case Unicode dans le fichier source), vous devriez générer un fichier UTF-8. (oui, les types de données internes devraient aussi être nvarchar, etc.).

Toutefois, le fichier généré à partir de SSIS ne comporte pas d'en-tête de nomenclature (marqueur d'ordre d'octet). Par conséquent, certains programmes présumeront qu'il est toujours au format ASCII et non UTF-8. J'ai vu cela confirmer par les employés MS sur MSDN , ainsi que par des tests. 

La solution "append file" est un moyen de contourner ce problème: en créant un fichier vide AVEC la nomenclature appropriée, puis en ajoutant des données à partir de SSIS, l'en-tête de la nomenclature reste en place. Si vous indiquez à SSIS de remplacer le fichier, il perd également la nomenclature.

Merci pour les conseils ici, cela m'a aidé à comprendre les détails ci-dessus.

5
Kristi Bittner

J'ai récemment travaillé sur un problème dans lequel nous rencontrons une situation telle que la suivante:

Vous travaillez sur une solution utilisant SQL Server Integration Services (Visual Studio 2005). Vous extrayez des données de votre base de données et essayez de les placer dans un fichier plat (.CSV) au format UTF-8. La solution exporte parfaitement les données et conserve les caractères spéciaux dans le fichier car vous avez utilisé 65001 comme page de code.

Toutefois, lorsque vous l'ouvrez ou tentez de le charger dans un autre processus, le fichier texte indique qu'il s'agit d'un fichier ANSI au lieu de UTF-8. Si vous ouvrez le fichier dans le bloc-notes et effectuez un SAVE AS et modifiez le codage en UTF-8, votre processus externe fonctionnera mais ce sera un travail manuel fastidieux.

Ce que j'ai constaté, c'est que lorsque vous spécifiez la propriété Page de code du gestionnaire de connexions de fichiers plats, celle-ci génère un fichier UTF-8. Cependant, il génère une version du fichier UTF-8 qui manque quelque chose que nous appelons Byte Order Mark.

Donc, si vous avez un fichier CSV contenant le caractère AA, la nomenclature pour UTF8 sera 0xef, 0xbb et 0xbf. Même si le fichier n’a pas de nomenclature, il reste UTF8.

Malheureusement, dans certains anciens systèmes hérités, les applications recherchent la nomenclature pour déterminer le type du fichier. Il semble que votre processus fasse de même.

Pour résoudre le problème, vous pouvez utiliser le code suivant dans votre tâche de script, qui peut être exécuté après le processus d'exportation.

using System.IO;

using System.Text;

using System.Threading;

using System.Globalization;

enter code here

static void Main(string[] args)
       {
           string pattern = "*.csv";
           string[] files = Directory.GetFiles(@".\", pattern, SearchOption.AllDirectories);
           FileCodePageConverter converter = new FileCodePageConverter();
           converter.SetCulture("en-US");
           foreach (string file in files)
           {
               converter.Convert(file, file, "Windows-1252"); // Convert from code page Windows-1250 to UTF-8  
           }  
       }

class FileCodePageConverter 
  { 
      public void Convert(string path, string path2, string codepage) 
      { 
          byte[] buffer = File.ReadAllBytes(path); 
          if (buffer[0] != 0xef && buffer[0] != 0xbb) 
          { 
              byte[] buffer2 = Encoding.Convert(Encoding.GetEncoding(codepage), Encoding.UTF8, buffer); 
              byte[] utf8 = new byte[] { 0xef, 0xbb, 0xbf }; 
              FileStream fs = File.Create(path2); 
              fs.Write(utf8, 0, utf8.Length); 
              fs.Write(buffer2, 0, buffer2.Length); 
              fs.Close(); 
          } 
      } 

      public void SetCulture(string name) 
      { 
          Thread.CurrentThread.CurrentCulture = new CultureInfo(name); 
          Thread.CurrentThread.CurrentUICulture = new CultureInfo(name); 
      } 
  }

lorsque vous exécuterez le package, vous constaterez que tous les CSV du dossier désigné seront convertis au format UTF8 contenant la marque d'ordre des octets.

De cette façon, votre processus externe sera capable de travailler avec les fichiers CSV exportés.

si vous ne recherchez qu'un dossier en particulier ... envoyez cette variable à une tâche de script et utilisez-la au-dessous d'un ..

      string sPath;

      sPath=Dts.Variables["User::v_ExtractPath"].Value.ToString();

      string pattern = "*.txt";

      string[] files = Directory.GetFiles(sPath);

J'espère que ça aide!!

4