 |
 |
11) Le système d’E/S de Java |
|
 |
|
Texte original |
 |
Traducteur :
Armel Fortun |
|
 |
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
//: c11:ClassScanner.java
// Scans all files in directory for classes
// and identifiers, to check capitalization.
// Assumes properly compiling code listings.
// Doesn't do everything right, but is a
// useful aid.
import java.io.*;
import java.util.*;
class MultiStringMap extends HashMap {
public void add(String key, String value) {
if(!containsKey(key))
put(key, new ArrayList());
((ArrayList)get(key)).add(value);
}
public ArrayList getArrayList(String key) {
if(!containsKey(key)) {
System.err.println(
"ERROR: can't find key: " + key);
System.exit(1);
}
return (ArrayList)get(key);
}
public void printValues(PrintStream p) {
Iterator k = keySet().iterator();
while(k.hasNext()) {
String oneKey = (String)k.next();
ArrayList val = getArrayList(oneKey);
for(int i = 0; i < val.size(); i++)
p.println((String)val.get(i));
}
}
}
public class ClassScanner {
private File path;
private String[] fileList;
private Properties classes = new Properties();
private MultiStringMap
classMap = new MultiStringMap(),
identMap = new MultiStringMap();
private StreamTokenizer in;
public ClassScanner() throws IOException {
path = new File(".");
fileList = path.list(new JavaFilter());
for(int i = 0; i < fileList.length; i++) {
System.out.println(fileList[i]);
try {
scanListing(fileList[i]);
} catch(FileNotFoundException e) {
System.err.println("Could not open " +
fileList[i]);
}
}
}
void scanListing(String fname)
throws IOException {
in = new StreamTokenizer(
new BufferedReader(
new FileReader(fname)));
// Doesn't seem to work:
// in.slashStarComments(true);
// in.slashSlashComments(true);
in.ordinaryChar('/');
in.ordinaryChar('.');
in.wordChars('_', '_');
in.eolIsSignificant(true);
while(in.nextToken() !=
StreamTokenizer.TT_EOF) {
if(in.ttype == '/')
eatComments();
else if(in.ttype ==
StreamTokenizer.TT_WORD) {
if(in.sval.equals("class") ||
in.sval.equals("interface")) {
// Get class name:
while(in.nextToken() !=
StreamTokenizer.TT_EOF
&& in.ttype !=
StreamTokenizer.TT_WORD)
;
classes.put(in.sval, in.sval);
classMap.add(fname, in.sval);
}
if(in.sval.equals("import") ||
in.sval.equals("package"))
discardLine();
else // It's an identifier or keyword
identMap.add(fname, in.sval);
}
}
}
void discardLine() throws IOException {
while(in.nextToken() !=
StreamTokenizer.TT_EOF
&& in.ttype !=
StreamTokenizer.TT_EOL)
; // Throw away tokens to end of line
}
// StreamTokenizer's comment removal seemed
// to be broken. This extracts them:
void eatComments() throws IOException {
if(in.nextToken() !=
StreamTokenizer.TT_EOF) {
if(in.ttype == '/')
discardLine();
else if(in.ttype != '*')
in.pushBack();
else
while(true) {
if(in.nextToken() ==
StreamTokenizer.TT_EOF)
break;
if(in.ttype == '*')
if(in.nextToken() !=
StreamTokenizer.TT_EOF
&& in.ttype == '/')
break;
}
}
}
public String[] classNames() {
String[] result = new String[classes.size()];
Iterator e = classes.keySet().iterator();
int i = 0;
while(e.hasNext())
result[i++] = (String)e.next();
return result;
}
public void checkClassNames() {
Iterator files = classMap.keySet().iterator();
while(files.hasNext()) {
String file = (String)files.next();
ArrayList cls = classMap.getArrayList(file);
for(int i = 0; i < cls.size(); i++) {
String className = (String)cls.get(i);
if(Character.isLowerCase(
className.charAt(0)))
System.out.println(
"class capitalization error, file: "
+ file + ", class: "
+ className);
}
}
}
public void checkIdentNames() {
Iterator files = identMap.keySet().iterator();
ArrayList reportSet = new ArrayList();
while(files.hasNext()) {
String file = (String)files.next();
ArrayList ids = identMap.getArrayList(file);
for(int i = 0; i < ids.size(); i++) {
String id = (String)ids.get(i);
if(!classes.contains(id)) {
// Ignore identifiers of length 3 or
// longer that are all uppercase
// (probably static final values):
if(id.length() >= 3 &&
id.equals(
id.toUpperCase()))
continue;
// Check to see if first char is upper:
if(Character.isUpperCase(id.charAt(0))){
if(reportSet.indexOf(file + id)
== -1){ // Not reported yet
reportSet.add(file + id);
System.out.println(
"Ident capitalization error in:"
+ file + ", ident: " + id);
}
}
}
}
}
}
static final String usage =
"Usage: \n" +
"ClassScanner classnames -a\n" +
"\tAdds all the class names in this \n" +
"\tdirectory to the repository file \n" +
"\tcalled 'classnames'\n" +
"ClassScanner classnames\n" +
"\tChecks all the java files in this \n" +
"\tdirectory for capitalization errors, \n" +
"\tusing the repository file 'classnames'";
private static void usage() {
System.err.println(usage);
System.exit(1);
}
public static void main(String[] args)
throws IOException {
if(args.length < 1 || args.length > 2)
usage();
ClassScanner c = new ClassScanner();
File old = new File(args[0]);
if(old.exists()) {
try {
// Try to open an existing
// properties file:
InputStream oldlist =
new BufferedInputStream(
new FileInputStream(old));
c.classes.load(oldlist);
oldlist.close();
} catch(IOException e) {
System.err.println("Could not open "
+ old + " for reading");
System.exit(1);
}
}
if(args.length == 1) {
c.checkClassNames();
c.checkIdentNames();
}
// Write the class names to a repository:
if(args.length == 2) {
if(!args[1].equals("-a"))
usage();
try {
BufferedOutputStream out =
new BufferedOutputStream(
new FileOutputStream(args[0]));
c.classes.store(out,
"Classes found by ClassScanner.java");
out.close();
} catch(IOException e) {
System.err.println(
"Could not write " + args[0]);
System.exit(1);
}
}
}
}
class JavaFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
// Strip path information:
String f = new File(name).getName();
return f.trim().endsWith(".java");
}
} ///:~
|
 |
//: c11:ClassScanner.java // Scanne tous les fichiers dans le répertoire pour les classes // et les identifiants, pour vérifier la capitalisation. // Présume des listes de code correctement compilées. // Ne fait pas tout bien, mais c'est // une aide utile. import java.io.*; import java.util.*;
class MultiStringMap extends HashMap { public void add(String key, String value) { if(!containsKey(key)) put(key, new ArrayList()); ((ArrayList)get(key)).add(value); } public ArrayList getArrayList(String key) { if(!containsKey(key)) { System.err.println( "ERROR: can't find key: " + key); System.exit(1); } return (ArrayList)get(key); } public void printValues(PrintStream p) { Iterator k = keySet().iterator(); while(k.hasNext()) { String oneKey = (String)k.next(); ArrayList val = getArrayList(oneKey); for(int i = 0; i < val.size(); i++) p.println((String)val.get(i)); } } }
public class ClassScanner { private File path; private String[] fileList; private Properties classes = new Properties(); private MultiStringMap classMap = new MultiStringMap(), identMap = new MultiStringMap(); private StreamTokenizer in; public ClassScanner() throws IOException { path = new File("."); fileList = path.list(new JavaFilter()); for(int i = 0; i < fileList.length; i++) { System.out.println(fileList[i]); try { scanListing(fileList[i]); } catch(FileNotFoundException e) { System.err.println("Could not open " + fileList[i]); } } } void scanListing(String fname) throws IOException { in = new StreamTokenizer( new BufferedReader( new FileReader(fname))); // Ne semble pas fonctionner : // in.slashStarComments(true); // in.slashSlashComments(true); in.ordinaryChar('/'); in.ordinaryChar('.'); in.wordChars('_', '_'); in.eolIsSignificant(true); while(in.nextToken() != StreamTokenizer.TT_EOF) { if(in.ttype == '/') eatComments(); else if(in.ttype == StreamTokenizer.TT_WORD) { if(in.sval.equals("class") || in.sval.equals("interface")) { // Prend le nom de la classe : while(in.nextToken() != StreamTokenizer.TT_EOF && in.ttype != StreamTokenizer.TT_WORD) ; classes.put(in.sval, in.sval); classMap.add(fname, in.sval); } if(in.sval.equals("import") || in.sval.equals("package")) discardLine(); else // C'est un identifiant ou un mot-clé identMap.add(fname, in.sval); } } } void discardLine() throws IOException { while(in.nextToken() != StreamTokenizer.TT_EOF && in.ttype != StreamTokenizer.TT_EOL) ; // Renvoie les tokens en fin de ligne } // Le déplacement des commentaire de StreamTokenizer semble // être cassé. Ceci les extrait : void eatComments() throws IOException { if(in.nextToken() != StreamTokenizer.TT_EOF) { if(in.ttype == '/') discardLine(); else if(in.ttype != '*') in.pushBack(); else while(true) { if(in.nextToken() == StreamTokenizer.TT_EOF) break; if(in.ttype == '*') if(in.nextToken() != StreamTokenizer.TT_EOF && in.ttype == '/') break; } } } public String[] classNames() { String[] result = new String[classes.size()]; Iterator e = classes.keySet().iterator(); int i = 0; while(e.hasNext()) result[i++] = (String)e.next(); return result; } public void checkClassNames() { Iterator files = classMap.keySet().iterator(); while(files.hasNext()) { String file = (String)files.next(); ArrayList cls = classMap.getArrayList(file); for(int i = 0; i < cls.size(); i++) { String className = (String)cls.get(i); if(Character.isLowerCase( className.charAt(0))) System.out.println( "class capitalization error, file: " + file + ", class: " + className); } } } public void checkIdentNames() { Iterator files = identMap.keySet().iterator(); ArrayList reportSet = new ArrayList(); while(files.hasNext()) { String file = (String)files.next(); ArrayList ids = identMap.getArrayList(file); for(int i = 0; i < ids.size(); i++) { String id = (String)ids.get(i); if(!classes.contains(id)) { // Ignore le identifiants de longeur 3 // qui sont majuscule sur tout leur longeur // (probablement des valeurs finales statiques) : if(id.length() >= 3 && id.equals( id.toUpperCase())) continue; // Vérifie pour voir si le premier cractère est majuscule : if(Character.isUpperCase(id.charAt(0))){ if(reportSet.indexOf(file + id) == -1){ // Ne rend pas encore compte reportSet.add(file + id); System.out.println( "Ident capitalization error in:" + file + ", ident: " + id); } } } } } } static final String usage = "Usage: \n" + "ClassScanner classnames -a\n" + "\tAdds all the class names in this \n" + "\tdirectory to the repository file \n" + "\tcalled 'classnames'\n" + "ClassScanner classnames\n" + "\tChecks all the java files in this \n" + "\tdirectory for capitalization errors, \n" + "\tusing the repository file 'classnames'"; private static void usage() { System.err.println(usage); System.exit(1); } public static void main(String[] args) throws IOException { if(args.length < 1 || args.length > 2) usage(); ClassScanner c = new ClassScanner(); File old = new File(args[0]); if(old.exists()) { try { // Essaye d'ouvir un fichier de // propriété existant : InputStream oldlist = new BufferedInputStream( new FileInputStream(old)); c.classes.load(oldlist); oldlist.close(); } catch(IOException e) { System.err.println("Could not open " + old + " for reading"); System.exit(1); } } if(args.length == 1) { c.checkClassNames(); c.checkIdentNames(); } // Écrit les noms de classe dans un dépôt : if(args.length == 2) { if(!args[1].equals("-a")) usage(); try { BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(args[0])); c.classes.store(out, "Classes found by ClassScanner.java"); out.close(); } catch(IOException e) { System.err.println( "Could not write " + args[0]); System.exit(1); } } } }
class JavaFilter implements FilenameFilter { public boolean accept(File dir, String name) { // Retire les infiormation de chemin : String f = new File(name).getName(); return f.trim().endsWith(".java"); } } ///:~
|
 |
 |
 |
The
class MultiStringMap is a tool that allows you to map a group of strings
onto each key entry. It uses a HashMap (this time with inheritance) with
the key as the single string that’s mapped onto the ArrayList
value. The add( ) method simply checks to see if there’s a key
already in the HashMap, and if not it puts one there. The
getArrayList( ) method produces an ArrayList for a particular
key, and printValues( ), which is primarily useful for debugging,
prints out all the values ArrayList by ArrayList.
|
 |
La classe MultiStringMap est un outil qui nous permet
d'organiser un groupe de chaînes de caractères sur chaque entrée de clé. Il utilise un
HashMap (cette fois avec héritage) avec la clé comme simple chaîne de caractère
qui est organisée sur la value de l'ArrayList. La méthode add()
vérifiesimplement si il y a déjà une clé dans le HashMap, si ce n'est pas le cas
elle en ajoute une à cet endroit. La méthode getArrayList() produit une
ArrayList pour une clé particulière, et printValues(), qui est
essentiellement utile pour le deboguage, affiche toutes les valeurs ArrayList par
ArrayList .
|
 |
 |
 |
To keep life simple, the class names from
the standard Java libraries are all put into a
Properties object (from the standard Java
library). Remember that a Properties object is a HashMap that
holds only String objects for both the key and value entries. However, it
can be saved to disk and restored from disk in one method call, so it’s
ideal for the repository of names. Actually, we need only a list of names, and a
HashMap can’t accept null for either its key or its value
entry. So the same object will be used for both the key and the
value.
|
 |
Pour avoir rester simple, les noms de classe des bibliothèques standard de
Java sont toutes placées dans un objet Properties (de la bibliothèque standard de
Java). Rappelons qu'un objet Properties est un HashMap qui ne
garde que des objetsString pour à la fois la clé et les valeurs d'entrée.
Cependant, il peut être sauvé vers le disque et restauré depuis le disque par un appel de méthode,
donc c'est l'idéal pour le dépôt des noms. Actuellement, on ne désire qu'une liste de noms, et un
HashMap ne peut pas accepter une null valeur à la fois pour ces
clés ou ces valeurs d'entrée.
|
 |
 |
 |
For the classes and identifiers that are
discovered for the files in a particular directory, two MultiStringMaps
are used: classMap and identMap. Also, when the program starts up
it loads the standard class name repository into the Properties object
called classes, and when a new class name is found in the local directory
that is also added to classes as well as to classMap. This way,
classMap can be used to step through all the classes in the local
directory, and classes can be used to see if the current token is a class
name (which indicates a definition of an object or method is beginning, so grab
the next tokens—until a semicolon—and put them into
identMap).
|
 |
Pour les classes et identifiants qui sont découvert pour les fichiers d'un
certain répertoire, deux MultiStringMaps sont utilisés : classMap et
identMap. Aussi, quand le programme démarre il charge le dépôt de nom de classe
standard dans l'objet Properties appelé classes, et quand un
nouveau nom de classe est découvert dans le répertoire local il est aussi ajouté à
classes en plus de classMap. De cette manière,
classMap peut être employé pour se déplacer à travers toutes les classes du
répertoire local, et classes peut être utilisé pour voir si le token courant est
un nom de classe (qui indique la définition d'un objet ou le début d'une méthode, donc saisit le
token suivant — jusqu'au point virgule — et le place dans
identMap).
|
 |
 |
 |
The default constructor for
ClassScanner creates a list of file names, using the JavaFilter
implementation of
FilenameFilter, shown at
the end of the file. Then it calls scanListing( ) for each file
name.
|
 |
Le constructeur par défaut pour ClassScanner crée une
liste de noms de fichier, en utilisant JavaFilter implémentation du
FilenameFilter, montré à la fin du fichier. Ensuite il appelle
scanListing() pour chaque nom de fichier.
|
 |
 |
 |
Inside scanListing( ) the
source code file is opened and turned into a
StreamTokenizer. In the
documentation, passing true to slashStarComments( ) and
slashSlashComments( ) is supposed to strip those comments out, but
this seems to be a bit flawed, as it doesn’t quite work. Instead, those
lines are commented out and the comments are extracted by another method. To do
this, the “/” must be captured as an ordinary character
rather than letting the StreamTokenizer absorb it as part of a comment,
and the ordinaryChar( ) method tells the StreamTokenizer
to do this. This is also true for dots (“.”),
since we want to have the method calls pulled apart into individual identifiers.
However, the underscore, which is ordinarily treated by StreamTokenizer
as an individual character, should be left as part of identifiers since it
appears in such static final values as TT_EOF, etc., used
in this very program. The wordChars( ) method takes a range of
characters you want to add to those that are left inside a token that is being
parsed as a word. Finally, when parsing for one-line comments or discarding a
line we need to know when an end-of-line occurs, so by calling
eolIsSignificant(true) the EOL will show up rather than being absorbed by
the StreamTokenizer.
|
 |
DansscanListing() le fichier de code source est ouvert et
transformé en un StreamTokenizer. Dans la documentation, passer
true de slashStarComments() à
slashSlashComments() est supposé enlever ces commentaires, mais cela semble être
quelque peu défectueux, car cela semble ne pas fonctionner. Au lieu de cela, ces lignes sont
marquées en tant que commentaires et les commentaires sont extrait par une autre méthode. Pour
cela, le « / » doit être capturé comme un caractère ordinaire plutôt que de laisser le
StreamTokenizer l'absorber comme une partie de commentaire, et la méthode
ordinaryChar() dit au StreamTokenizer de faire cela. C'est aussi
vrai pour les points (« . »), vu que nous voulons que l'appel de la méthode soit séparé en
deux en identifiants individuels. Pourtant, l'underscore (soulignement), qui est ordinairement
traité par StreamTokenizer comme un caractère individuel, doit être laissé comme
une partie des identifiants puisqu'il apparaît dans des valeurs static
final comme TT_EOF, etc., employé dans tant de nombreux
programmes. La méthode wordChars() prend une rangée de caractères que l'on désire
ajouter à ceux qui sont laissé dans un token qui à) été analysé comme un mot. Finalement, lorsqu'on
fait l'analyse pour une ligne de commentaire ou que l'on met de coté une ligne on veux savoir quand
arrive la fin de ligne, c'est pourquoi en appelant eolIsSignificant(true) l'EOL
(End Of Line : fin de ligne) apparaîtra plutôt que sera absorbé par le
StreamTokenizer.
|
 |
 |
 |
The rest of scanListing( )
reads and reacts to tokens until the end of the file, signified when
nextToken( ) returns the final static value
StreamTokenizer.TT_EOF.
|
 |
Le reste du scanListing() lit et réagit aux tokens jusqu'à
la fin du fichier, annonçant quand nextToken() renvoie la valeur final
static StreamTokenizer.TT_EOF.
|
 |
 |
 |
If the token is a “/” it is
potentially a comment, so eatComments( ) is called to deal with it.
The only other situation we’re interested in here is if it’s a word,
of which there are some special cases.
|
 |
Si le token est un « / » il est potentiellement un commentaire,
donc eatComments() est appelé pour voir avec lui. La seule autre situation qui
nous intéresse est quand il s'agit d'un mot, sur lequel il y a des cas spéciaux.
|
 |
 |
 |
If the word is class or
interface then the next token represents a class or interface name, and
it is put into classes and classMap. If the word is import
or package, then we don’t want the rest of the line. Anything else
must be an identifier (which we’re interested in) or a keyword (which
we’re not, but they’re all lowercase anyway so it won’t spoil
things to put those in). These are added to identMap.
|
 |
Si le mot est class ou interface alors le
prochain token représente une classe ou une interface, et il est placé dans
classes et classMap. Si le mot est import ou
package, alors on n'a plus besoin du reste de la ligne. Tout le reste doit être un
identifiant (auquel nous sommes intéressé) ou un mot-clé (qui ne nous intéresse pas, mais ils sont
tous en minuscule de toutes manières donc cela n'abîmera rien de les placer dedans). Ceux-ci sont
ajoutés à identMap.
|
 |
 |
 |
The discardLine( ) method is
a simple tool that looks for the end of a line. Note that any time you get a new
token, you must check for the end of the file.
|
 |
La méthode discardLine() est un outil simple qui cherche
la fin de ligne. Notons que caque fois que l'on trouve un nouveau token, l'on doit effectuer le
contrôle de la fin de ligne.
|
 |
 |
 |
The eatComments( ) method is
called whenever a forward slash is encountered in the main parsing loop.
However, that doesn’t necessarily mean a comment has been found, so the
next token must be extracted to see if it’s another forward slash (in
which case the line is discarded) or an asterisk. But if it’s neither of
those, it means the token you’ve just pulled out is needed back in the
main parsing loop! Fortunately, the
pushBack( ) method
allows you to “push back” the current token onto the input stream so
that when the main parsing loop calls
nextToken( ) it will
get the one you just pushed back.
|
 |
La méthode eatComments() est appelée toutes les fois qu'un
slash avant est rencontré dans la boucle d"analyse principale. Cependant, cela ne veut pas
forcément dire qu'un commentaire ai été trouvé, donc le prochain token doit être extrait pour voir
si c'est un autre slash avant (dans ce cas la ligne est rejetée) ou un astérisque. Mais si c'est
n'est pas l'un d'entre eux, cela signifie que le token qui vient d'être sorti est nécessaire dans
la boucle d'analyse principale ! Heureusement, la pushBack() méthode nous permet
de « pousser en arrière » le token courant dans le flux d'entrée pour que quand la boucle
d'analyse principale appelle nextToken() elle prendra celui que l'on viens tout
juste de pousser en arrière.
|
 |
 |
 |
For convenience, the
classNames( ) method produces an array of all the names in the
classes container. This method is not used in the program but is helpful
for debugging.
|
 |
Par commodité, la méthode produit un tableau de tous les noms dans le
récipient classes. Cette méthode n'est pas utilisée dans le programme mais est
utiles pour le déboguage.
|
 |
 |
 |
The next two methods are the ones in
which the actual checking takes place. In checkClassNames( ), the
class names are extracted from the classMap (which, remember, contains
only the names in this directory, organized by file name so the file name can be
printed along with the errant class name). This is accomplished by pulling each
associated ArrayList and stepping through that, looking to see if the
first character is lowercase. If so, the appropriate error message is
printed.
|
 |
Les deux prochaines méthodes sont celles dans lesquelles prend place la
réelle vérification. Dans checkClassNames(), les noms des classe sont extraits
depuis le classMap (qui, rappelons le, contient seulement les noms dans ce
répertoire, organisés par nom de fichier de manière à ce que le nom de fichier puisse être imprimé
avec le nom de classe errant). Ceci est réalisé en poussant chaque ArrayList
associé et en allant plus loin que ça, en regardant pour voir si le premier caractère est en
minuscule. Si c'est le cas, le message approprié est imprimé.
|
 |
 |
 |
In checkIdentNames( ), a
similar approach is taken: each identifier name is extracted from
identMap. If the name is not in the classes list, it’s
assumed to be an identifier or keyword. A special case is checked: if the
identifier length is three or more and all the characters are uppercase,
this identifier is ignored because it’s probably a static
final value such as TT_EOF. Of course, this is not a perfect
algorithm, but it assumes that you’ll eventually notice any all-uppercase
identifiers that are out of place.
|
 |
Dans checkIdentNames(), une approche similaire est prise :
chaque nom d'identifiant est extrait depuis identMap. Si le nom n'est pas dans la
liste classes, il est supposé être un identifiant ou un mot-clé. Un cas spécial
est vérifié : si la longueur de l'identifiant est trois et tout les caractères sont en majuscule,
cette identifiant est ignoré puisqu'il est probablement une valeur static
final comme TT_EOF. Bien sur, ce n'est pas un algorithme parfait,
mais il assume que l'on avertira par la suite de tous les identifiants complétement-majuscules qui
sont hors sujet.
|
 |
 |
 |
Instead of reporting every identifier
that starts with an uppercase character, this method keeps track of which ones
have already been reported in an ArrayList called
reportSet( ). This treats the ArrayList as a
“set” that tells you whether an item is already in the set. The item
is produced by concatenating the file name and identifier. If the element
isn’t in the set, it’s added and then the report is
made.
|
 |
Au lieu de reporter tout les identifiants qui commencent par un caractère
majuscule, cette méthode garde trace de celles qui ont déjà été rapportées dans
ArrayList appelées reportSet(). Ceci traite
l'ArrayList comme un « jeu » qui vous signale lorsqu'un élément se
trouve déjà dans le jeu. L'élément est produit en ajoutant au nom de fichier l'identifiant. Si
l'élément n'est pas dans le jeu, il est ajouté puis un le rapport est effectué.
|
 |
 |
 |
The rest of the listing is comprised of
main( ), which busies itself by handling the command line arguments
and figuring out whether you’re building a repository of class names from
the standard Java library or checking the validity of code you’ve written.
In both cases it makes a ClassScanner object.
|
 |
Le reste du listing est composé de main(), qui s'en occupe
lui même en manipulant les arguments de ligne de commande et prenant en compte de l'endroit où l'on
a construit le dépôt de noms de classe de la bibliothèque standard Java ou en vérifiant la validité
du code que l'on a écrit. Dans les deux cas il fait un objet
ClassScanner.
|
 |
 |
 |
Whether you’re building a
repository or using one, you must try to open the existing repository. By making
a File object and testing
for existence, you can decide whether to open the file and load( )
the Properties list classes inside ClassScanner. (The
classes from the repository add to, rather than overwrite, the classes found by
the ClassScanner constructor.) If you provide only one command-line
argument it means that you want to perform a check of the class names and
identifier names, but if you provide two arguments (the second being
“-a”) you’re building a class name repository.
In this case, an output file is opened and the method
Properties.save( ) is used to write the list into a file, along with
a string that provides header file
information.
|
 |
Si l'on construit ou utilisons un dépôt, on doit essayer d'ouvrir les
dépôts existants. En créant un objet File et en testant son existence, on peut
décider que l'on ouvre le fichier et load() la liste de classes
Properties dans ClassScanner. (Les classes du dépôt s'ajoutent, ou plutôt
recouvrent, les classes trouvées par le constructeur ClassScanner.) Si l'on
fournit seulement un seul argument en ligne de commande cela signifie que l'on désire accomplir une
vérification des noms de classes et d'identifiants, mais si l'on fournit deux arguments (le second
étant un « -a ») on construit un dépôt de noms de classes. Dans ce cas, un
fichier de sortie est ouvert et la méthode Properties.save() est utilisée pour
écrire la liste dans un fichier, avec une chaîne de caractère fournissant l'information d'en tête
du fichier.
|
 |
 |
 |
Summary
|
 |
Résumé
|
 |
 |
 |
The Java I/O stream library does satisfy
the basic requirements: you can perform reading and writing with the console, a
file, a block of memory, or even across the Internet (as you will see in Chapter
15). With inheritance, you can create new types of input and output objects. And
you can even add a simple extensibility to the kinds of objects a stream will
accept by redefining the toString( ) method that’s
automatically called when you pass an object to a method that’s expecting
a String (Java’s limited “automatic type conversion”).
|
 |
La bibliothèque Java de flux d'E/S satisfait les exigence de base : on peut
faire la lecture et l'écriture avec la console, un fichier, un bloc de mémoire, ou même à travers
l'Internet (comme on pourra le voir au Chapitre 15). Avec l'héritage, on peut créer de nouveaux
types d'objets d'entrée et de sortie. Et l'on peut même ajouter une simple extension vers les types
d'objets qu'un flux pourrait accepter en redéfinissant la méthode toString() qui
est automatiquement appelée lorsque l'on passe un objet à une méthode qui attendait un
String (« conversion automatique de type » limitée à Java).
|
 |
 |
 |
There are questions left unanswered by
the documentation and design of the I/O stream library. For example, it would
have been nice if you could say that you want an exception thrown if you try to
overwrite a file when opening it for output—some programming systems allow
you to specify that you want to open an output file, but only if it
doesn’t already exist. In Java, it appears that you are supposed to use a
File object to determine whether a file exists, because if you open it as
a FileOutputStream or FileWriter it will always get
overwritten.
|
 |
Il y a des questions laissées sans réponses par la documentation et la
conception de la bibliothèque de flux. Par exemple, il aurait été agréable de pouvoir dire que l'on
désire lancer une exception si l'on essaye d'écrire par dessus un fichier en l'ouvrant pour la
sortie – certains systèmes de programmation permettant de spécifier que l'on désire ouvrir un
fichier de sortie, mais seulement si il n'existe pas déjà. En Java, il apparaît que l'on est
supposé utiliser un objet File pour déterminer qu'un fichier existe, puisque si on
l'ouvre comme un FileOutputStream ou un FileWriter il sera
toujours écrasé.
|
 |
 |
 |
The I/O stream library brings up mixed
feelings; it does much of the job and it’s portable. But if you
don’t already understand the decorator pattern, the design is
nonintuitive, so there’s extra overhead in learning and teaching it.
It’s also incomplete: there’s no support for the kind of output
formatting that almost every other language’s I/O package supports.
|
 |
La bibliothèque de flux d'E/S amène des sentiments mélangés ; elle fait
plus de travail et est portable. Mais si vous ne comprenez pas encore le decorator pattern, la
conception n'est pas intuitive, il y a donc des frais supplémentaires pour l'apprendre et
l'enseigner. Elle est aussi incomplète : il n'y a pas de support pour le genre de format de sortie
que presque chaque paquetage d'E/S d'autres langages supportent.
|
 |
 |
 |
However, once you do understand
the decorator pattern and begin using the library in situations that require its
flexibility, you can begin to benefit from this design, at which point its cost
in extra lines of code may not bother you as much.
|
 |
Cependant, dès que vous pourrez comprendre le decorator pattern et
commencerez à utiliser la bibliothèque pour des situations demandant sa flexibilité, vous pourrez
commencer a bénéficier de cette conception, à tel point que ce que ça vous coûtera en lignes de
codes supplémentaires ne vous ennuiera pas beaucoup.
|
 |
 |
 |
If you do not find what you’re
looking for in this chapter (which has only been an introduction, and is not
meant to be comprehensive), you can find in-depth coverage in Java I/O,
by Elliotte Rusty Harold (O’Reilly,
1999).
|
 |
Si vous n'avez pas trouvé ce que vous cherchiez dans ce chapitre (qui a
seulement été une introduction, et n'est pas censée être complète), vous pourrez trouver une
couverture détaillé dans Java E/S, de Elliotte Rusty Harold (O’Reilly,
1999).
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |