Le maniement des chars et des strings en langage C, c'était déjà une grande aventure. Elle a donné lieu à l'écriture souvent hardue de tout un tas de DLL. Entre les chars signés, les chars non signés, le maniement du texte était une affaire de spécialistes, je ne parle pas d'internationnalisation.
Malheureusement et même si en C# les librairies strings se sont intégrées au framework .NET. Elles apportent un soutient sans commune mesure. Il semble qu'un certain nombres de choses ne soient pas correctement résolues !
Problème :
Voilà le code que j'incrimine, il s'agit simplement d'écrire un texte dans la réponse sous forme de fichier pour l'enregistrer sur votre disque dur :
protected void ButtonCreateCSV_OnClick( object sender, System.EventArgs e )
{
Response.ContentType = "text/plain";
Response.AddHeader( "content-disposition", "attachment; filename=\"" + "monfichier.txt" + "\"" );
Response.Write( "Nom prénom : Râleur né" );
Response.End();
}
Après un clic sur le bouton, le fichier qui en résult que vous pouvez téléchargé sur votre pc est pourri ! On retrouve un bug récurrent sur la plateforme Windows.
Le "é" est codé en hexa E9 après cette opération, il est "explosé" en 2 octets qui vont perturber tous les éditeurs de texte :
Nom prénom : Râleur né
Sachant que :
L'objet string est au format Unicode, encore que, des formats unicode il y en a plusieurs !
Que un simple éditeur va lire correctement de l'UTF-8 ou 7 le code à écrire est simplement :
string s = "Nom prénom : Râleur né";
byte[] unicodeBytes = Encoding.Unicode.GetBytes( s );
byte[] utf7Bytes = Encoding.Convert( Encoding.Unicode, Encoding.UTF7, unicodeBytes );
Response.BinaryWrite( utf7Bytes );
Et là cela ne marche pas ! Et là je sais pas pourquoi !
Solution :
Voici le code que je me suis amusé à écrire
protected void TEST_ButtonCreateCSV_OnClick( object sender, System.EventArgs e )
{
Response.ContentType = "text/plain";
Response.AddHeader( "content-disposition", "attachment; filename=\"" + TextBoxFileNameCSV.Text + "\"" );
string sb = "Nom prénom : Râleur né";
char[] chars = sb.ToCharArray();
byte[] bytes = new byte[ chars.Length ];
for ( int i = 0;i < chars.Length;i++ )
bytes[ i ] = ( byte )chars[ i ];
Response.BinaryWrite( bytes );
Response.End();
}
Pour quoi ça marche ?
Je dirais simplement qu'il me semble que 'E' s'écrit en binaire 1110 avec un bit de poid fort à 1. La fonction Write déclenche un carry overflow et le E9 se retrouve sur 2 octets. Bon c'est pas très clair mais c'est sûrement un peu ça.
En passant un tableau de byte à la fonction BinairyWrite le problème ne se pose plus.
La solution ne m'enchante pas plus que cela mais au moins ça marche !
Je vous recommande un lien sur les formats avant de critiquer ce post :
http://sebsauvage.net/python/charsets_et_encoding.html
En effet une page HTML est en UTF-8 ça je sais, on voudrait tous travailler avec de l'Unicode mais certaines applications travaillent avec quel codage ?
De plus l'unicode n'est pas le codage qui prend le moins de place en mémoire !