• Aucun résultat trouvé

3 Classes NET d'usage courant

3.6 Les fichiers binaires

Les classes System.IO.BinaryReader et System.IO.BinaryWriter servent à lire et écrire des fichiers binaires. Considérons l'application suivante :

// syntaxe pg texte bin logs

// le fichier texte a des lignes de la forme nom : age qu'on rangera dans une structure string, int // (logs) est un fichier texte de logs

Le fichier texte a le contenu suivant : 1. paul : 10 2. helene : 15 3. 4. jacques : 11 5. sylvain : 12 6. xx : -1 7. 8. xx: yy : zz 9. xx : yy

Le programme est le suivant : 1. using System; 2. using System.IO; 3.

4. // syntaxe pg texte bin logs

5. // on lit un fichier texte (texte) et on range son contenu dans un fichier binaire (bin)

6. // le fichier texte a des lignes de la forme nom : age qu'on rangera dans une structure string, int

7. // (logs) est un fichier texte de logs 8.

9. namespace Chap3 { 10. class Program {

11. static void Main(string[] arguments) { 12. // il faut 3 arguments

13. if (arguments.Length != 3) {

14. Console.WriteLine("syntaxe : pg texte binaire log");

15. Environment.Exit(1);

16. }//if

17.

18. // variables 19. string ligne=null; 20. string nom=null; 21. int age=0;

22. int numLigne = 0;

23. char[] séparateurs = new char[] { ':' }; 24. string[] champs=null;

25. StreamReader input = null;

26. BinaryWriter output = null;

27. StreamWriter logs = null;

28. bool erreur = false;

29. // lecture fichier texte - écriture fichier binaire 30. try {

31. // ouverture du fichier texte en lecture 32. input = new StreamReader(arguments[0]); 33. // ouverture du fichier binaire en écriture

34. output = new BinaryWriter(new FileStream(arguments[1], FileMode.Create, FileAccess.Write));

35. // ouverture du fichier des logs en écriture 36. logs = new StreamWriter(arguments[2]); 37. // exploitation du fichier texte

38. while ((ligne = input.ReadLine()) != null) { 39. // une ligne de plus

40. numLigne++; 41. // ligne vide ? 42. if (ligne.Trim() == "") { 43. // on ignore 44. continue; 45. }

46. // une ligne nom : age

47. champs = ligne.Split(séparateurs); 48. // il nous faut 2 champs

49. if (champs.Length != 2) {

50. // on logue l'erreur

51. logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un nombre de champs incorrect", numLigne, arguments[0]);

52. // ligne suivante

53. continue;

54. }//if

55. // le 1er champ doit être non vide 56. erreur = false;

57. nom = champs[0].Trim(); 58. if (nom == "") {

59. // on logue l'erreur

60. logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un nom vide", numLigne, arguments[0]);

61. erreur = true;

62. }

63. // le second champ doit être un entier >=0 64. if (!int.TryParse(champs[1],out age) || age<0) {

65. // on logue l'erreur

66. logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un âge [{2}] incorrect", numLigne, arguments[0], champs[1].Trim());

67. erreur = true;

68. }//if

69. // si pas d'erreur, on écrit les données dans le fichier binaire

70. if (!erreur) { 71. output.Write(nom); 72. output.Write(age); 73. } 74. // ligne suivante 75. }//while

76. }catch(Exception e){

77. Console.WriteLine("L'erreur suivante s'est produite : {0}", e.Message); 78. } finally {

79. // fermeture des fichiers 80. if(input!=null) input.Close(); 81. if(output!=null) output.Close(); 82. if(logs!=null) logs.Close();

83. }

84. }

85. } 86. }

Attardons-nous sur les opérations concernant la classe BinaryWriter :ligne 34 : l'objet BinaryWriter est ouvert par l'opération

output=new BinaryWriter(new FileStream(arguments[1],FileMode.Create,FileAccess.Write)); L'argument du constructeur doit être un flux (Stream). Ici c'est un flux construit à partir d'un fichier (FileStream) dont on donne :

o le nom

o l'opération à faire, ici FileMode.Create pour créer le fichier

o le type d'accès, ici FileAccess.Write pour un accès en écriture au fichier  lignes 70-73 : les opérations d'écriture

// on écrit les données dans le fichier binaire output.Write(nom);

output.Write(age);

La classe BinaryWriter dispose de différentes méthodes Write surchargées pour écrire les différents types de données simples  ligne 81 : l'opération de fermeture du flux

output.Close();

Les trois arguments de la méthode Main sont donnés au projet (via ses propriétés) [1] et le fichier texte à exploiter est placé dans le dossier bin/Release [2] :

Avec le fichier [personnes1.txt] suivant : 1. paul : 10 2. helene : 15 3. 4. jacques : 11 5. sylvain : 12 6. xx : -1 7. 8. xx: yy : zz 9. xx : yy

les résultats de l'exécution sont les suivants :

• en [1], le fichier binaire [personnes1.bin] créé ainsi que le fichier de logs [logs.txt]. Celui-ci a le contenu suivant : 1. La ligne n° [6] du fichier [personnes1.txt] a un âge [-1] incorrect

2. La ligne n° [8] du fichier [personnes1.txt] a un nombre de champs incorrect 3. La ligne n° [9] du fichier [personnes1.txt] a un âge [yy] incorrect

Le contenu du fichier binaire [personnes1.bin] va nous être donné par le programme qui suit. Celui-ci accepte également trois arguments :

// syntaxe pg bin texte logs

// on lit un fichier binaire bin et on range son contenu dans un fichier texte (texte) // le fichier binaire a une structure string, int

// le fichier texte a des lignes de la forme nom : age // logs est un fichier texte de logs

On fait donc l'opération inverse. On lit un fichier binaire pour créer un fichier texte. Si le fichier texte produit est identique au fichier originel on saura que la conversion texte --> binaire --> texte s'est bien passée. Le code est le suivant :

1. using System; 2. using System.IO; 3.

4. // syntaxe pg bin texte logs

5. // on lit un fichier binaire bin et on range son contenu dans un fichier texte (texte) 6. // le fichier binaire a une structure string, int

1

2

7. // le fichier texte a des lignes de la forme nom : age 8. // logs est un fichier texte de logs

9.

10.namespace Chap3 { 11. class Program2 {

12. static void Main(string[] arguments) { 13. // il faut 3 arguments

14. if (arguments.Length != 3) {

15. Console.WriteLine("syntaxe : pg binaire texte log");

16. Environment.Exit(1);

17. }//if

18.

19. // variables 20. string nom = null; 21. int age = 0;

22. int numPersonne = 1;

23. BinaryReader input = null;

24. StreamWriter output = null;

25. StreamWriter logs = null;

26. bool fini;

27. // lecture fichier binaire - écriture fichier texte 28. try {

29. // ouverture du fichier binaire en lecture

30. input = new BinaryReader(new FileStream(arguments[0], FileMode.Open, FileAccess.Read)); 31. // ouverture du fichier texte en écriture

32. output = new StreamWriter(arguments[1]); 33. // ouverture du fichier des logs en écriture 34. logs = new StreamWriter(arguments[2]); 35. // exploitation du fichier binaire 36. fini = false; 37. while (!fini) { 38. try { 39. // lecture nom 40. nom = input.ReadString().Trim(); 41. // lecture age 42. age = input.ReadInt32();

43. // écriture dans fichier texte 44. output.WriteLine(nom + ":" + age); 45. // personne suivante 46. numPersonne++; 47. } catch (EndOfStreamException) { 48. fini = true; 49. } catch (Exception e) {

50. logs.WriteLine("L'erreur suivante s'est produite à la lecture de la personne n° {0} : {1}", numPersonne, e.Message);

51. }

52. }//while

53. } catch (Exception e) {

54. Console.WriteLine("L'erreur suivante s'est produite : {0}", e.Message); 55. } finally {

56. // fermeture des fichiers 57. if (input != null) 58. input.Close(); 59. if (output != null) 60. output.Close(); 61. if (logs != null) 62. logs.Close(); 63. } 64. } 65. } 66. }

Attardons-nous sur les opérations concernant la classe BinaryReader :ligne 30 : l'objet BinaryReader est ouvert par l'opération

input=new BinaryReader(new FileStream(arguments[0],FileMode.Open,FileAccess.Read));

L'argument du constructeur doit être un flux (Stream). Ici c'est un flux construit à partir d'un fichier (FileStream) dont on donne :

• le nom

l'opération à faire, ici FileMode.Open pour ouvrir un fichier existantle type d'accès, ici FileAccess.Read pour un accès en lecture au fichier

 lignes 40, 42 : les opérations de lecture nom=input.ReadString().Trim();

age=input.ReadInt32();

La classe BinaryReader dispose de différentes méthodes ReadXX pour lire les différents types de données simples  ligne 60 : l'opération de fermeture du flux

input.Close();

Si on exécute les deux programmes à la chaîne transformant personnes1.txt en personnes1.bin puis personnes1.bin en personnes2.txt2 on obtient les résultats suivants :

• en [1], le projet est configuré pour exécuter la 2ième application • en [2], les arguments passés à Main

• en [3], les fichiers produits par l'exécution de l'application. Le contenu de [personnes2.txt] est le suivant :

1. paul:10 2. helene:15 3. jacques:11 4. sylvain:12