Les Flux D'entrée-Sortie
Les Flux D'entrée-Sortie
Les Flux D'entrée-Sortie
Accueil Cours Apprenez programmer en Java Les flux d'entre/sortie
Je ne vous cache pas qu'il existe une foule dobjets qui ont chacun leur faon de travailler avec les flux.
Sachez que Java a dcompos les objets traitant des flux en deux catgories :
les objets travaillant avec des flux d'entre ( in ), pour la lecture de flux ;
les objets travaillant avec des flux de sortie ( out ), pour l'criture de flux.
Utilisation de java.io
L'objet File
Avant de commencer, crez un fichier avec l'extension que vous voulez et enregistrez-le la racine de
votre projet Eclipse. Personnellement, je me suis fait un fichier test.txt dont voici le contenu :
java
Dans votre projet Eclipse, faites un clic droit sur le dossier de votre projet, puis New>File . Vous
pouvez nommer votre fichier ainsi qu'y taper du texte !
Le nom du dossier contenant mon projet s'appelle IO et mon fichier texte est cette adresse :
D:\Mesdocuments\Codage\SDZ\Java-SDZ\IO\test.txt . Nous allons maintenant voir ce dont
l'objet File est capable. Vous remarquerez que cet objet est trs simple utiliser et que ses mthodes
sont trs explicites.
java
Vous conviendrez que les mthodes de cet objet peuvent s'avrer trs utiles ! Nous venons d'en essayer
quelques-unes et nous avons mme list les sous-fichiers et sous-dossiers de nos lecteurs la racine du
PC.
Vous pouvez aussi effacer le fichier grce la mthode delete() , crer des rpertoires avec la mthode
mkdir() (le nom donn ce rpertoire ne pourra cependant pas contenir de point ( . )) etc.
Maintenant que vous en savez un peu plus sur cet objet, nous pouvons commencer travailler avec
notre fichier !
Ces classes hritent des classes abstraites InputStream et OutputStream , prsentes dans le
package java.io .
Comme vous l'avez sans doute devin, il existe une hirarchie de classes pour les traitements in et une
autre pour les traitements out . Ne vous y trompez pas, les classes hritant d' InputStream sont
destines la lecture et les classes hritant d' OutputStream se chargent de l'criture !
Vous auriez dit le contraire ? Comme beaucoup de gens au dbut. Mais c'est uniquement parce que vous
situez les flux par rapport vous, et non votre programme ! Lorsque ce dernier va lire des informations
dans un fichier, ce sont des informations qu'il reoit, et par consquent, elles s'apparentent une
entre : in (sachez tout de mme que lorsque vous tapez au clavier, cette action est considre comme
un flux d'entre !).
Nous allons enfin commencer travailler avec notre fichier. Le but est d'aller en lire le contenu et de le
copier dans un autre, dont nous spcifierons le nom dans notre programme, par le biais d'un programme
Java.
Notez bien les imports pour pouvoir utiliser ces objets. Mais comme vous le savez dj, vous pouvez
taper votre code et faire ensuite CTRL + SHIFT + O pour que les imports soient automatiques.
l'excution de ce code, vous pouvez voir que le fichier test2.txt a bien t cr et qu'il contient
exactement la mme chose que test.txt ! De plus, j'ai ajout dans la console les donnes que votre
programme va utiliser (lecture et criture).
Copie de fichier
Le bloc finally permet de s'assurer que nos objets ont bien ferm leurs liens avec leurs fichiers
respectifs, ceci afin de permette Java de dtruire ces objets pour ainsi librer un peu de mmoire
votre ordinateur.
En effet, les objets utilisent des ressources de votre ordinateur que Java ne peut pas librer de
lui-mme, vous devez tre sr que la vanne est ferme ! Ainsi, mme si une exception est leve,
le contenu du bloc finally sera excut et nos ressources seront libres. Par contre, pour
allger la lecture, je ne mettrai plus ces blocs dans les codes venir mais pensez bien les
mettre dans vos codes.
Les objets FileInputStream et FileOutputStream sont assez rudimentaires, car ils travaillent avec
un nombre dtermin d'octets lire. Cela explique pourquoi ma condition de boucle tait si tordue
Lorsque vous voyez des caractres dans un fichier ou sur votre cran, ils ne veulent pas dire grand-chose
pour votre PC, car il ne comprend que le binaire (vous savez, les suites de 0 et de 1). Ainsi, afin de pouvoir
afficher et travailler avec des caractres, un systme d'encodage (qui a d'ailleurs fort volu) a t mis au
point.
Sachez que chaque caractre que vous saisissez ou que vous lisez dans un fichier correspond un code
binaire, et ce code binaire correspond un code dcimal. Voyez la table de correspondance (on parle de
la table ASCII).
Cependant, au dbut, seuls les caractres de a z, de A Z et les chiffres de 0 9 (les 127 premiers
caractres de la table ASCII) taient cods (UNICODE 1), correspondant aux caractres se trouvant dans
la langue anglaise. Mais ce codage s'est rapidement avr trop limit pour des langues comportant des
caractres accentus (franais, espagnol). Un jeu de codage de caractres tendu a donc t mis en
place afin de pallier ce problme.
Chaque code binaire UNICODE 1 est cod sur 8 bits, soit 1 octet. Une variable de type byte , en Java,
correspond en fait 1 octet et non 1 bit !
Les objets que nous venons d'utiliser emploient la premire version d'UNICODE 1 qui ne comprend pas
les caractres accentus, c'est pourquoi ces caractres ont un code dcimal ngatif dans notre fichier.
Lorsque nous dfinissons un tableau de byte 8 entres, cela signifie que nous allons lire 8 octets la
fois.
Vous pouvez voir qu' chaque tour de boucle, notre tableau de byte contient huit valeurs
correspondant chacune un code dcimal qui, lui, correspond un caractre (valeur entre parenthses
ct du code dcimal).
Vous pouvez voir que les codes dcimaux ngatifs sont inconnus, car ils sont reprsents par des ? ;
de plus, il y a des caractres invisibles (les 32 premiers caractres de la table ASCII sont invisibles !) dans
notre fichier :
Vous voyez que les traitements des flux suivent une logique et une syntaxe prcises ! Lorsque nous avons
copi notre fichier, nous avons rcupr un certain nombre d'octets dans un flux entrant que nous avons
pass un flux sortant. chaque tour de boucle, les donnes lues dans le fichier source sont crites dans
le fichier dfini comme copie.
Il existe prsent des objets beaucoup plus faciles utiliser, mais qui travaillent nanmoins avec les
deux objets que nous venons d'tudier. Ces objets font galement partie de la hirarchie cite
prcdemment. Seulement, il existe une superclasse qui les dfinit.
Vous pouvez voir qu'il existe quatre classes filles hritant de FilterInputStream (de mme pour
FilterOutputStream (les classes drivant de FilterOutputStream ont les mmes
fonctionnalits, mais en criture)):
DataInputStream : offre la possibilit de lire directement des types primitifs ( double , char
, int ) grce des mthodes comme readDouble() , readInt()
BufferedInputStream : cette classe permet d'avoir un tampon disposition dans la lecture du
flux. En gros, les donnes vont tout d'abord remplir le tampon, et ds que celui-ci est plein, le
programme accde aux donnes.
PushbackInputStream : permet de remettre un octet dj lu dans le flux entrant.
LineNumberInputStream : cette classe offre la possibilit de rcuprer le numro de la ligne
lue un instant T.
Ces classes prennent en paramtre une instance drivant des classes InputStream (pour les classes
hritant de FilterInputStream ) ou de OutputStream (pour les classes hritant de
FilterOutputStream ).
Puisque ces classes acceptent une instance de leur superclasse en paramtre, vous pouvez cumuler les
filtres et obtenir des choses de ce genre :
java
Afin de vous rendre compte des amliorations apportes par ces classes, nous allons lire un norme
fichier texte (3,6 Mo) de faon conventionnelle avec l'objet vu prcdemment, puis grce un buffer.
Tlcharger le fichier
La diffrence de temps est vraiment norme : 1,578 seconde pour la premire mthode et 0,094 seconde
pour la deuxime ! Vous conviendrez que l'utilisation d'un buffer permet une nette amlioration des
performances de votre code. Faisons donc sans plus tarder le test avec lcriture :
java
L, la diffrence est encore plus nette, comme le montre la figure suivante.
Je ne vais pas passer en revue tous les objets cits un peu plus haut, mais vu que vous risquez davoir
besoin des objets Data(Input/Output)Stream , nous allons les aborder rapidement, puisqu'ils
s'utilisent comme les objets BufferedInputStream . Je vous ai dit plus haut que ceux-ci ont des
mthodes de lecture pour chaque type primitif : il faut cependant que le fichier soit gnr par le biais
d'un DataOutputStream pour que les mthodes fonctionnent correctement.
Nous allons donc crer un fichier de toutes pices pour le lire par la suite.
java
La figure suivante correspond au rsultat de ce code.
Le code est simple, clair et concis. Vous avez pu constater que ce type d'objet ne manque pas de
fonctionnalits ! Jusqu'ici, nous ne travaillions qu'avec des types primitifs, mais il est galement possible
de travailler avec des objets !
Qu'est-ce que c'est que cette interface ? Tu n'as mme pas implment de mthode !
En fait, cette interface n'a pas de mthode redfinir : l'interface Serializable est ce qu'on appelle
une interface marqueur . Rien qu'en implmentant cette interface dans un objet, Java sait que cet
objet peut tre srialis. Et j'irai mme plus loin : si vous n'implmentez pas cette interface dans vos
objets, ceux-ci ne pourront pas tre srialiss ! En revanche, si une superclasse implmente l'interface
Serializable , ses enfants seront considrs comme srialisables.
Vous avez srement dj senti comment vous allez vous servir de ces objets, mais travaillons tout de
mme sur lexemple que voici :
java
La dsrialisation d'un objet peut engendrer une ClassNotFoundException , pensez donc
la capturer !
Srialisation dsrialisation
Ce qu'il se passe est simple : les donnes de vos objets sont enregistres dans le fichier. Mais que se
passerait-il si notre objet Game avait un autre objet de votre composition en son sein ? Voyons a tout
de suite. Crez la classe Notice comme suit :
java
Nous allons maintenant implmenter une notice par dfaut dans notre objet Game . Voici notre classe
modifie :
java
Ressayez votre code sauvegardant vos objets Game . La figure suivante nous montre le rsultat obtenu.
Erreur de srialisation
Eh non, votre code ne compile plus ! Il y a une bonne raison cela : votre objet Notice n'est pas
srialisable, une erreur de compilation est donc leve. Maintenant, deux choix s'offrent vous :
Pour la premire option, c'est simple, il suffit d'implmenter l'interface srialisable dans notre classe
Notice . Pour la seconde, il suffit de dclarer votre variable : transient ; comme ceci :
java
Vous aurez sans doute remarqu que nous n'utilisons pas la variable notice dans la mthode
toString() de notre objet Game . Si vous faites ceci, que vous srialisez puis dsrialisez vos
objets, la machine virtuelle vous renverra lexception NullPointerException l'invocation
de ladite mthode. Eh oui ! L'objet Notice est ignor : il n'existe donc pas !
CharArray(Writer/Reader) ;
String(Writer/Reader) .
Ces deux types jouent quasiment le mme rle. De plus, ils ont les mmes mthodes que leur classe
mre. Ces deux objets n'ajoutent donc aucune nouvelle fonctionnalit leur objet mre.
Leur principale fonction est de permettre d'crire un flux de caractres dans un buffer adaptatif : un
emplacement en mmoire qui peut changer de taille selon les besoins (nous n'en avons pas parl dans le
chapitre prcdent afin de ne pas l'alourdir, mais il existe des classes remplissant le mme rle que ces
classes-ci : ByteArray(Input/Output)Stream ).
Je vous laisse le soin d'examiner ce code ainsi que son effet. Il est assez comment pour que vous en
compreniez toutes les subtilits. L'objet String(Writer/Reader) fonctionne de la mme faon :
java
En fait, il s'agit du mme code, mais avec des objets diffrents ! Vous savez prsent comment crire un
flux de texte dans un tampon de mmoire. Je vous propose maintenant de voir comment traiter les
fichiers de texte avec des flux de caractres.
Depuis le JDK 1.4, un nouveau package a vu le jour, visant amliorer les performances des flux, buffers,
etc. traits par java.io . En effet, vous ignorez probablement que le package que nous explorons
depuis le dbut existe depuis la version 1.1 du JDK. Il tait temps d'avoir une remise niveau afin
d'amliorer les rsultats obtenus avec les objets traitant les flux. C'est l que le package java.nio a vu
le jour !
Utilisation de java.nio
Vous l'avez srement devin, nio signifie New I/O . Comme je vous l'ai dit prcdemment, ce
package a t cr afin d'amliorer les performances sur le traitement des fichiers, du rseau et des
buffers. Il permet de lire les donnes (nous nous intresserons uniquement l'aspect fichier) d'une faon
diffrente. Vous avez constat que les objets du package java.io traitaient les donnes par octets. Les
objets du package java.nio , eux, les traitent par blocs de donnes : la lecture est donc acclre !
Tout repose sur deux objets de ce nouveau package : les channels et les buffers. Les channels sont en fait
des flux, tout comme dans l'ancien package, mais ils sont amens travailler avec un buffer dont vous
dfinissez la taille. Pour simplifier au maximum, lorsque vous ouvrez un flux vers un fichier avec un objet
FileInputStream , vous pouvez rcuprer un canal vers ce fichier. Celui-ci, combin un buffer, vous
permettra de lire votre fichier encore plus vite qu'avec un BufferedInputStream !
Reprenez le gros fichier que je vous ai fait crer dans la sous-section prcdente : nous allons maintenant
le relire avec ce nouveau package en comparant le buffer conventionnel et la nouvelle faon de faire.
java
La figure suivante vous montre le rsultat.
Vous constatez que les gains en performance ne sont pas ngligeables. Sachez aussi que ce nouveau
package est le plus souvent utilis pour traiter les flux circulant sur les rseaux. Je ne m'attarderai pas
sur le sujet, mais une petite prsentation est de mise. Ce package offre un buffer par type primitif pour la
lecture sur le channel, vous trouverez donc ces classes :
IntBuffer ;
CharBuffer ;
ShortBuffer ;
ByteBuffer ;
DoubleBuffer ;
FloatBuffer ;
LongBuffer .
Je ne l'ai pas fait durant tout le chapitre afin d'allger un peu les codes, mais si vous voulez tre srs que
votre flux est bien ferm, utilisez la clause finally . Par exemple, faites comme ceci :
java
Avec l'arrive de Java 7, quelques nouveauts ont vu le jour pour la gestion des exceptions sur les flux.
Contrairement la gestion de la mmoire (vos variables, vos classes, etc.) qui est dlgue au garbage
collector (ramasse miette), plusieurs types de ressources doivent tre gres manuellement. Les flux sur
des fichiers en font parti mais, d'un point de vue plus gnral, toutes les ressources que vous devez
fermer manuellement (les flux rseaux, les connexions une base de donnes). Pour ce genre de flux,
vous avez vu qu'il vous faut dclarer une variable en dehors d'un bloc try{}catch{} afin qu'elle
soit accessible dans les autres blocs d'instructions, le bloc finally par exemple.
Java 7 initie ce qu'on appelle vulgairement le try-with-resources . Ceci vous permet de dclarer les
ressources utilises directement dans le bloc try() , ces dernires seront automatiquement fermes
la fin du bloc d'instructions ! Ainsi, si nous reprenons notre code de dbut de chapitre qui copie notre
fichier test.txt vers test2.txt , nous aurons ceci :
java
Notez bien que les diffrentes ressources utilises sont spares par un ; dans le bloc try !
C'est tout de mme beaucoup plus clair et plus lisible qu'avant, surtout que vous n'avez plus vous
soucier de la fermeture dans le bloc finally . Il faut cependant prendre quelques prcautions
notamment pour ce genre de dclaration :
java
Le fait d'avoir des ressources encapsules dans d'autres ne rend pas visible les ressources
encapsules. Dans le cas prcdent, si une exception est leve, le flux correspondant l'objet
FileInputStream ne sera pas ferm. Pour pallier ce problme il suffit de bien dcouper toutes les
ressources utiliser, comme ceci :
java
Rien ne vous chappe ! Si j'ai chang de faon de faire c'est parce qu'il y a une restriction sur ce mode de
fonctionnement. Pour rendre la fermeture automatique possible, les dveloppeurs de la plateforme Java
7 ont cr une nouvelle interface : java.lang.AutoCloseable . Seuls les objets implmentant cette
interface peuvent tre utiliss de la sorte ! Vous pouvez voir la liste des classes autorises cette adresse
(et vous constaterez que la classe File n'en fait pas parti).
L'une des grandes nouveauts de Java 7 rside dans NIO.2 avec un nouveau package java.nio.file
en remplacement de la classe java.io.File . Voici un bref listing de quelques nouveauts :
une meilleure gestion des exceptions : la plupart des mthodes de la classe File se contentent
de renvoyer une valeur nulle en cas de problme, avec ce nouveau package, des exceptions seront
leves permettant de mieux cibler la cause du (ou des) problme(s) ;
un accs complet au systme de fichiers (support des liens/liens symboliques, etc.) ;
l'ajout de mthodes utilitaires tels que le dplacement/la copie de fichier, la lecture/criture
binaire ou texte
rcuprer la liste des fichiers d'un rpertoire via un flux ;
remplacement de la classe java.io.File par l'interface java.nio.file.Path .
Je vous propose maintenant de jouer avec quelques nouveauts. Commenons par le commencement :
ce qui finira par remplacer la classe File . Afin d'tre le plus souple et complet possible, les
dveloppeurs de la plateforme ont cr une interface java.nio.file.Path dont le rle est de
rcuprer et manipuler des chemins de fichiers de dossier et une une classe java.nio.file.Files
qui contient tout un tas de mthodes qui simplifient certaines actions (copie, dplacement, etc.) et
permet aussi de rcuprer tout un tas d'informations sur un chemin.
Afin d'illustrer ce nouveau mode de fonctionnement, je vous propose de reprendre le premier exemple
de ce chapitre, celui qui affichait diffrentes informations sur notre fichier de test.
java
La classe Files vous permet aussi de lister le contenu d'un rpertoire mais via un objet
DirectoryStream qui est un itrateur. Ceci vite de charger tous les fichiers en mmoire pour
rcuprer leurs informations. Voici comment procder :
java
Vous avez galement la possibilit d'ajouter un filtre votre listing de rpertoire afin qu'il ne liste que
certains fichiers :
java
C'est vrai que cela change grandement la faon de faire et elle peut paratre plus complexe. Mais l'objet
Files simplifie aussi beaucoup de choses. Voici quelques exemple de mthodes utilitaires qui, je
pense, vont vous sduire.
La copie de fichier
Le troisime argument permet de spcifier les options de copie. Voici celles qui sont disponibles :
Le dplacement de fichier
Java 7 vous permet galement de grer les fichier ZIP grce l'objet FileSystem :
java
Il est galement possible d'tre averti via l'objet WatchService lorsqu'un un fichier est modifi, de
grer des entres/sorties asynchrones via les objets AsynchronousFileChannel ,
AsynchronousSocketChannel ou AsynchronousServerSocketChannel . Ceci permet de faire les
actions en tche de fond, sans bloquer le code pendant l'excution. Il est aussi possible d'avoir accs aux
attributs grce 6 vues permettant de voir plus ou moins d'informations, savoir :
BasicFileAttributeView permet un accs aux proprits gnralement communes tous
les systmes de fichiers ;
DosFileAttributeView ajoute le support des attributs MS-DOS ( readonly , hidden ,
system , archive ) l'objet ci-dessus ;
PosixFileAttributeView ajoute les permissions POSIX du monde Unix au premier objet cit ;
FileOwnerAttributeView permet de manipuler le propritaire du fichier ;
AclFileAttributeView permet de manipuler les droits d'accs au fichier ;
UserDefinedFileAttributeView : permet de dfinir des attributs personnaliss.
Le pattern decorator
Vous avez pu remarquer que les objets de ce chapitre utilisent des instances d'objets de mme
supertype dans leur constructeur. Rappelez-vous cette syntaxe :
java
La raison d'agir de la sorte est simple : c'est pour ajouter de faon dynamique des fonctionnalits un
objet. En fait, dites-vous qu'au moment de rcuprer les donnes de notre objet DataInputStream ,
celles-ci vont d'abord transiter par les objets passs en paramtre. Ce mode de fonctionnement suit une
certaine structure et une certaine hirarchie de classes : c'est le pattern decorator.
Ce pattern de conception permet d'ajouter des fonctionnalits un objet sans avoir modifier son code
source. Afin de ne pas trop vous embrouiller avec les objets tudis dans ce chapitre, je vais vous fournir
un autre exemple, plus simple, mais gardez bien en tte que les objets du package java.io utilisent ce
pattern. Le but du jeu est d'obtenir un objet auquel nous pourrons ajouter des choses afin de le dcorer
Vous allez travailler avec un objet Gateau qui hritera d'une classe abstraite Patisserie . Le but
du jeu est de pouvoir ajouter des couches notre gteau sans avoir modifier son code source.
Vous avez vu avec le pattern strategy que la composition ( A un ) est souvent prfrable l'hritage (
Est un ) : vous aviez dfini de nouveaux comportements pour vos objets en crant un supertype d'objet
par comportement. Ce pattern aussi utilise la composition comme principe de base : vous allez voir que
nos objets seront composs d'autres objets. La diffrence rside dans le fait que nos nouvelles
fonctionnalits ne seront pas obtenues uniquement en crant de nouveaux objets, mais en associant
ceux-ci des objets existants. Ce sera cette association qui crera de nouvelles fonctionnalits !
Tout cela dmarre avec un concept fondamental : l'objet de base et les objets qui le dcorent doivent
tre du mme type, et ce, toujours pour la mme raison, le polymorphisme, le polymorphisme, et le
polymorphisme !
Vous allez comprendre. En fait, les objets qui vont dcorer notre gteau possderont la mme mthode
preparer() que notre objet principal, et nous allons faire fondre cet objet dans les autres. Cela
signifie que nos objets qui vont servir de dcorateurs comporteront une instance de type Patisserie ;
ils vont englober les instances les unes aprs les autres et du coup, nous pourrons appeler la mthode
preparer() de manire rcursive !
Vous pouvez voir les dcorateurs comme des poupes russes : il est possible de mettre une poupe dans
une autre. Cela signifie que si nous dcorons notre gateau avec un objet CoucheChocolat et un objet
CoucheCaramel , la situation pourrait tre symbolise par la figure suivante.
L'objet CoucheCaramel contient l'instance de la classe CoucheChocolat qui, elle, contient l'instance
de Gateau : en fait, on va passer notre instance d'objet en objet ! Nous allons ajouter les fonctionnalits
des objets dcorants en appelant la mthode preparer() de l'instance se trouvant dans l'objet
avant d'effectuer les traitements de la mme mthode de l'objet courant, comme la figure suivante.
Nous verrons, lorsque nous parlerons de la classe Thread , que ce systme ressemble fortement la
pile d'invocations de mthodes. La figure suivante montre quoi ressemble le diagramme de classes de
notre exemple.
Diagramme de classes
Vous remarquez sur ce diagramme que notre classe mre Patisserie est en fait la strategy (une classe
encapsulant un comportement fait rfrence au pattern strategy : on peut dire qu'elle est la strategy de
notre hirarchie) de notre structure, c'est pour cela que nous pourrons appeler la mthode
preparer() de faon rcursive afin d'ajouter des fonctionnalits nos objets. Voici les diffrentes
classes que j'ai utilises (je n'ai utilis que des String afin de ne pas surcharger les sources, et pour
que vous vous focalisiez plus sur la logique que sur le code).
Patisserie.java
java
Gateau.java
java
Couche.java
java
CoucheChocolat.java
java
CoucheCaramel.java
java
CoucheBiscuit.java
java
Et voici un code de test ainsi que son rsultat, reprsent la figure suivante.
java
Rsultat du test
J'ai agrment l'exemple d'une couche de biscuit, mais je pense que tout cela est assez reprsentatif de
la faon dont fonctionnent des flux d'entre/sortie en Java. Vous devriez russir saisir tout cela sans
souci. Le fait est que vous commencez maintenant avoir en main des outils intressants pour
programmer, et c'est sans compter les outils du langage : vous venez de mettre votre deuxime pattern
de conception dans votre mallette du programmeur.
Vous avez pu voir que l'invocation des mthodes se faisait en allant jusqu'au dernier lment pour
remonter ensuite la pile d'invocations. Pour inverser ce fonctionnement, il vous suffit d'inverser les
appels dans la mthode preparer() : affecter d'abord le nom de la couche et ensuite le nom du
dcorateur.
Le professeur
Cyrille Herby
Spcialiste en dveloppement Java et curieux insatiable dinformatique et de programmation web.
Actuellement auditeur en scurit.
Premium
eBook Livre papier PDF
English Espaol