Regular expression is
JDK 1.4's new features, but for the standard utility of the UNIX like the SED and AWK, and the language such as Python, Perl, it has already become an indispensable component (someone even thinks, it is still Perl can be a major reason for successful reasons). From a technical point of view, the regular expression is just a tool for processing a string (past
Java this task is
String,
StringBuffer and
StringTokenizer processed, but it often uses I / O, so it is not too proposed to put it here.
[66]
Regular expressions are a powerful but very flexible text handling tool. It allows you to describe the complex text mode with programming, then find it in the string. Once you find this mode, you can deal with these texts as you want. Although the syntax of the regular expression is a bit daunting, it provides a refined dynamic language that allows us to solve the problem of various strings in a common way, including matching, selection, editing, and check.
Create regular expressions
You can learn the regular expression from a relatively simple thing. To comprehensively master how to build a regular expression, you can go to the document of the JDK document Java.util.Regex's Pattern class.
Character B character B / XHH16 enumeration value 0xHH represented character / uhhhh16 enumeration value 0xHHHH represents Unicode characters / TTAB / N wrap / R carrier / f switch / EESCAPE
The power of regular expressions can define the character class. Here are some of the most common character sets and their definitions, and there are some predefined character sets:
The character set. Represents any one of the characters [ABC] represents any one of characters a, b, and c (same as A | B | C) [^ ABC] except for any character other than A, B, C [Negate) [ A-ZA-Z] Any of the characters (range) from A to Z or A to Z [ABC [Hij]] A, B, C, H, I, J (with A | B | C | H | i | j The same) (pag) [A-Z && [Hij]] H, I, J (intersection) / s space character (space bar, tab, wrap, switching, Enter) / S non-space characters ([^ / s]) / D a number, that is, [0-9] / d, a non-digital character, that is, [^ 0-9] / W a word character (Word Character), That is, [a-za-z_0-9] / w, a non-word character, [^ / W]
If you have used the regular expression of other languages, then you can see that the backslash is different. In other languages, "//" means "I just want to insert a backslash in the regular expression. Nothing special meaning." But in Java, "//" means "I want to insert one Regular expression of the backslash, so the meaning of the character following it will change. "For example, if you want to represent one or more" word characters ", then this regular expression should be" // w ". If you want to insert a backslash, you have to use "". However, it is still like a wrap, and a backgrou is still only one backslash: "/ n / t".
I only give you an example here; you should add Java.util.Regex.pattern to the JDK document to your favorites, which can easily find a variety of regular expressions.
The logical operator XYX followed by YX | YX or Y (x) a "capturing group". You can use / i later to represent the i-i-matched group.
Boundary matching characters ^ One line of start $ The end of the end / b A word boundary / b A non-word boundary / g Previous match ends End of a specific example. The following regular expressions are legal, and they can match "rudolph":
Rudolph
[rr] udolph
[rr] [aeiou] [a-z] ip *
R. *
Quantity representation
"Quantifier" role is to define how many characters should be matched.
Greedy: Unless otherwise indicated, the quantity indicator is GREEDY. Greedy's expression will match until it does not match. (If you find the result of expression and expectations), it is very likely because you think that the expression only matches the front several characters, and it is actually Greedy, so it will match. Reluctant: Decorating the question mark that it will match the least character. Also known as Lazy, Minimal Matching, Non-Greedy, or Ungreedy. Possessive: currently only Java support (other languages are not supported). It is more advanced, so you may not use it. Many intermediate states are generated when the string is matched by the regular expression, and this intermediate state will be saved.) When such a match fails, it will be returned. The possession expression does not save this intermediate state, so it will not turn back. It prevents the failure of regular expressions and improves operational efficiency.
GREEDY RELUCTANT POSSSIVE Match X? X ?? x? Match One or Zero XX * X *? X * Match Zero or Multiple X X X ? X Match One or more xx {n} x {n}? X {n} matching just n xx {n,} x {n,}? x {n,} match at least n xx {n, m} x {n, m}? x {n, m} match At least n, at most M x
Remind you, want to let the expression you mean, you should put the 'x' with brackets. for example:
ABC
It seems that this expression can match one or a number of 'ABC', but if you really use it to match 'Abcabcabc', you will only find three characters. Because this expression means 'ab', follows one or more 'c'. To match one or more complete 'ABC', you should do this:
(ABC)
Regular expressions can be played easily; this is a new language built on Java.
Charsequence
JDK 1.4 defines a new interface called Charsequence. It provides abstraction of the string and stringbuffer two classes of characters:
Interface charsequence {
Charat (INT I);
Length ();
Subsequence (int start, int end);
Tostring ();
}
In order to achieve this new Charsequence interface, String, StringBuffer, and Charbuffer have made modifications. Many regular expressions are taken to take Charsequence for parameters.
Pattern and Matcher
First give an example. The following program can test whether the regular expression matches the string. The first parameter is the string to match, and the back is the regular expression. Regular expressions can be multiple. In a UNIX / Linux environment, regular expressions under the command line must also use quotation marks.
When you create a regular expression, you can use this program to determine whether it will work according to your requirements.
//: C12: TestRegularExpression.java// allows you to easly try out regular expression.
// {args: abcabcabcdefabc "abc " "(abc) " (abc) {2,} "}
Import java.util.regex. *;
Public class testRegularExpression {
Public static void main (String [] args) {
IF (args.length <2) {
System.out.println ("USAGE: / N"
"Java TestRegularExpression"
"CharacterSequence RegularExpression ");
System.exit (0);
}
System.out.println ("INPUT: /" Args [0] "/" ");
For (int i = 1; i System.out.println ( "Regular expression: /" " args [i] " / ""); Pattern P = Pattern.Compile (Args [i]); Matcher m = p.matcher (args [0]); While (M.Find ()) { System.out.println ("match /" m.group () "/" AT Positions " M.START () "-" (M.End () - 1)); } } } } ///: ~ Java's regular expression is implemented by the Pattern and Matcher of Java.util.Regex. The Pattern object represents the compiled regular expression. The static compile () method is responsible for compiling a string representing the regular expression into a pattern object. As shown in the above routines, you can get a Matcher object as long as you send a string to the matcher () method of Pattern. In addition, Pattern has a quick judgment that can find regex in Input (note, the original text is incorrect, missed method name) Static Boolean Matches (Regex, INPUT) And the SPLIT () method that returns the String array, which can be separated by regex. Just send a string to the pattern.matcher () method to get the Matcher object. Next, you can query the result of the match with Matcher. Boolean matches () Boolean loopsat () Boolean Find () Boolean Find (int Start) The premise of matches () is that pattern matches the entire string, and lookingat () means the beginning of the Pattern matches string. Find () Matcher.find () features a plurality of character sequences that matches the PatternNence in CharSequern. E.g: //: c12: finddemo.java Import java.util.regex. *; Import com.bruceeckel.simpletest. *; Import java.util. *; Public class finddemo {private static test monitor = new test (); Public static void main (String [] args) { Matcher M = Pattern.Compile ("// w ") .matcher ("EVENING IS FULL of the Linnet's Wings"); While (m.find ()) System.out.println (M.Group ()); INT i = 0; While (M.Find (i)) { System.out.print (M.Group () ""); i ; } Monitor.expect (new string "{ "EVening", "IS", "fulll", "of", "THE", "linnet", "s", "Wings", "EVENING VENING ENING ING NG G IS Is S Full" "Full Ull Ll L of F THE THE HE E Linnet Linnet" "Innet NNET NET ET T S S Wings Wings INGS NGS GS S" }); } } ///: ~ "// w " means "one or more word characters", so it will decompose the string into words. Find () scans over the string from head until tail. The second Find () is with int parameter, as you can see, it will tell the method where to start looking - starting from the parameter location. Groups Group refers to the regular expressions that are enclosed in parentheses and can be called behind. Group 0 represents the entire expression, and Group 1 represents the first group that is pushed in this class. and so; A (B (c)) D There are three groups: group 0 is ABCD, Group 1 is BC, group 2 is C. You can use the following Matcher method to use Group: Public int groupCount () Returns the number of Groups in the Matcher object. Does not include Group0. Public string group () Returns the last matching operation (for all, Find ()) Group 0 (entire match) Public String Group (INT i) Returns a Group for the last match. If the match is successful, but you have not found a group, then return NULL. Public int start (int group) Returns the starting position of the group found last time. Public int end (int 201) Returns the last position of the game found, the last character's subscript is added. Let's give some examples of Group: //: C12: Groups.java Import java.util.regex. *; Import com.bruceeckel.simpletest. *; Public class groups { Private static test monitor = new test (); Static Public Final String Poem = "TWAS Brillig, and The Slithy Toves / N" "DID GYRE AND GIMBLE I WABE./N" "All Mimsy Were the Borogoves, / N" "And the Mome Raths Outgrabe./n/N" "BEWARE THE JABBERWOCK, My SON, / N" "THE JAWS THAT BITE, THE CLAWS THAT Catch./N" "BEWARE THE JUBJUB BIRD, And SHUN / N" "The frumious bandersnatch." Public static void main (String [] args) { Matcher M = Pattern.Compile ("(? M) (// s ) // s (// s ) // s (// s )) ___ fckpd___9quot;) .MATCHER (POEM); While (M.Find ()) { For (int J = 0; j <= m.GroupCount (); J ) System.out.print ("[[" m.Group (j) "]"); SYSTEM.OUT.PRINTLN (); } Monitor.expect (new string "{ "[the slithy toves]" "[the] [slithy Toves] [slithy] [TOVES]", [in the Wabe.] [The Wabe.] [THE] [WABE.] "[were the borogoves,]" "[WERE] [The borogoves,] [the] [borogoves,]", "[MOME Raths Outgrabe.]" "[MOME] [Raths Outgrabe.] [outgrabe.], "[Jabberwock, My Son,]" "[Jabberwock,] [my Son,] [my] [SON,]", [Claws That catch.] " "[CLAWS] [That Catch.] [That] [Catch.]", "[Bird, And Shun] [Bird,] [and Shun] [SHUN]", "[The frumious bandersnatch.] [The]" [frumious bandersnatch.] [frumious] [bandersnatch.] " }); } } ///: ~ This poem is the first part of "jabberwocky" of Through the loops Glass, Lewis Carroll. It can be seen that there are many groups enclosed in parentheses, which is composed of any plurality of consecutive non-empty characters ('/ s ') and any plurality of consecutive space characters ('/ s '). The final purpose is to capture the last three words of each row; '$' represents the end of a row. But '$' typically represents the end of the entire string, so it is clear that the regular expression will pay attention to the online character. This is done by '(? M)' flag (the pattern mark will explain for a while). Start () and end () If the match is successful, start () will return the start position of this match, and End () will return the end position of this match, that is, the last character's subscript is added. If the previous match is unsuccessful (or there is no match), then an ILLEGALSTATEEXCEPTION is triggered whether it is called start () or end (). The following program also demonstrates matches () and loowsingat (): //: C12: StarTend.java Import java.util.regex. *; Import com.bruceeckel.simpletest. *; Public class startend { Private static test monitor = new test (); Public static void main (String [] args) { String [] input = new string [] { "Java Has Regular Expressions IN 1.4", "Regular Expressions Now Expressing in Java", "Java Replesses Oracular Expressions" } Pattern P1 = pattern.Compile ("RE // w *"), P2 = pattern.Compile ("java. *"); For (int i = 0; i System.out.println ("INPUT" i ":" Input [i]); Matcher M1 = p1.matcher (Input [i]), M2 = p2.matcher (Input [i]); While (m1.find ()) System.out.println ("m1.find () '" m1.group () "'start =" m1.Start () "end =" m1.end ()); While (m2.find ()) System.out.println ("M2.Find ()" m2.group () "'start =" m2.Start () "end =" m2.end ()); IF (m1.lookingat ()) // no reset () Necessary System.out.println ("m1.lookingat () start =" m1.Start () "end =" m1.end ()); if (m2.lookingat ()) System.out.println ("m2.lookingat () start =" m2.Start () "end =" m2.end ()); IF (matches ()) // no reset () Necessary System.out.println ("M1.MATCHES () START =" m1.Start () "end =" m1.end ()); IF (m2.matches ()) System.out.println ("m2.matches () st =" m2.Start () "end =" m2.end ()); } Monitor.expect (new string "{ "INPUT 0: Java Has Regular Expressions in 1.4", "m1.find () 'regular' start = 9 End = 16", "m1.find () 'relassions' start = 20 End = 28", "M2.Find () 'Java Has Regular Expressions in 1.4'" "START = 0 end = 35", "m2.lookingat () st = 0 end = 35", "m2.matches () st = 0 end = 35", "Input 1: Regular Expressions Now" "Expressing in Java", "m1.find () 'regular' start = 0 end = 7", "m1.find () 'relassion' start = 11 end = 19", "m1.find () 'relassing' start = 27 end = 34", "m2.find () 'java' start = 38 end = 42", "m1.lookingat () st = 0 end = 7", "Input 2: Java Represses Oracular Expressions", "m1.find () 'represses' start = 5 End = 14", "m1.find () 'RESSONS' START = 27 end = 35", "M2.Find () 'Java Represses Oracular Expressions' "START = 0 end = 35", "m2.lookingat () st = 0 end = 35", "m2.matches () st = 0 end = 35"}); } } ///: ~ Note that as long as this mode is in the string, Find () can find it, but loowsingat () and matches (), only if the string matches the regular expression, you can return TRUE. The premise of matches () success is that the regular expression is fully matched with the string, and the premise of the relayat () [67] success is that the start portion of the string matches the regular expression. Match mode (Pattern Flags) The Compile () method has a version that requires a parameter that controls the matching behavior of the regular expression: Pattern Pattern.Compile (String Regex, INT FLAG) The value range of FLAG is as follows: Compilation marker effect pattern.canon_eq When only the "Canonical Decomient" "is exactly the same, the match is determined. For example, after using this logo, the expression "A / U030A" will match "?". By default, "canonical Equivalence" is not considered. Pattern.case_insensitive (? I) By default, case-sensitive matches are only available for US-ASCII character sets. This logo allows expressions to ignore cases to match. If you want to match the Unicode characters, you will line up with the unicode_case with this flag. Pattern.comments (? X) In this mode, the space character is ignored (the translator note: not "// s" in the expression, but refers to the expression in the expression. Space, Tab, Enter the Enter). Note From # beginning, until this line ends. UniX row mode can be enabled by embedded markers. Pattern.dotall (? S) In this mode, the expression '.' Can match any character, including the end of the line. By default, the expression '.' Does not match the end of the line. Pattern.Multiline (? M) In this mode, '^' and '$' each match the beginning and end of the row. In addition, '^' still matches the beginning of the string, '$' also matches the end of the string. By default, these two expressions simply match the beginning and end of the string. Pattern.unicode_case (? U) In this mode, if you also enable the Case_InSensitive flag, it will match the Unicode characters and unlikely. By default, case-in-case disseminated matches are only available for US-ASCII character sets. Pattern.unix_Lines (? D) In this mode, only '/ n' is considered to be aborted, and match '.', '^', And '$'. In these symbols, pattern.case_insensitive, pattern.multiline, and pattern.comments are the most useful (where pattern.comments can help us clearly, and / or do documents). Note that you can use the vast majority of modes in the way in the expression. These marks are below the respective signs of the table above. Where do you want the model to start starting, where is it. These markers can be used with "OR" ('|') operator: //: C12: Reflags.java Import java.util.regex. *; Import com.bruceeckel.simpletest. *; Public class reflags { Private static test monitor = new test (); Public static void main (String [] args) { Pattern P = Pattern.Compile ("^ java", Pattern.case_insensitive | pattern.multiline; Matcher m = p.matcher "Java Has Regex / NJAVA HAS REGEX / N" "Java Has Pretty Good Regular Expressions / N" "Regular Expressions Are In Java); While (m.find ()) System.out.println (M.Group ()); Monitor.expect (new string "{ "Java", "Java", "Java" }); } } ///: ~ This created regular expression can match the string of "Java", "Java", "Java" .... In addition, if the character string is a few lines, it will match each row (the match begins with the start of the character sequence, and finally the line end of the character sequence). Note that the group () method returns only the matching part. Split () The so-called segmentation means that the string is divided into a String array in a regular expression. String [] split (charsequence charseq) String [] split (charsequence charseq, int limit) This is a way to split the text according to some common boundary markers. //: c12: splitDemo.java Import java.util.regex. *; Import com.bruceeckel.simpletest. *; Import java.util. *; Public class splitdemo { Private static test monitor = new test (); Public static void main (String [] args) { String input = "This !! unusual use !! of exclamation !! points"; System.out.println (arrays.aslist) Pattern.Compile ("!!"). Split (input))); // only do the first three: System.out.println (arrays.aslist) Pattern.Compile ("!!"). Split (Input, 3))); System.out.println (arrays.aslist) "AHA! STRING HAS a split () Built in!". Split ("))); Monitor.expect (new string "{ "[This, unusual use, of exclamation, points], "[This, Unusual Use, of Exclamation !! Points]", "[AHA!, String, HAS, A, Split (), Built, In!] }); } } ///: ~ The second split () will limit the number of segments. The regular expression is so important, so that some features are added to the String class, including split () (have been seen), Matches (), replacefirst (), and replaceall (). The functions of these methods are the same as Pattern and Matcher. Replacement operation Regular expressions are especially in the replacement text. Here is some ways: Replacefirst (String Replacement) replaces the string of the string, the first match matching the subsidence to Replacement. ReplaceAll (String Replacement), replacing all substrings that match the input string into Replacement. AppendReplacement (StringBuffer SBUF, String Replacement) replaces SBUF, rather than REPLACEFIRST () or ReplaceAll () only replaces only the first or all substrings. This is a very important method because it can call methods to generate Replacement (ReplaceFirst () and ReplaceAll () only allows a fixed string to act as Replacement. With this method, you can program the Group to achieve more powerful replacement. After calling appendreplacement (), in order to copy the remaining string, you must call appendtail (StringBuffer Sbuf, String Replacement). Let's demonstrate how to use these replacement methods. Explanation, the string processed by this program is a comment on its own head. It is extracted with the regular expression and processes it to the replacement method. //: C12: Thereplacements.java Import java.util.regex. *; Import java.io. *; Import com.bruceeckel.util. *; Import com.bruceeckel.simpletest. *; / *! Here's a block of text to use as input to The regular expression matcher. Note That We'll First Extract The Block of Text by Looking for For THE SPECIAL DELIMITERS, THEN Process EXTRACTED block.! * / Public class theretements { Private static test monitor = new test (); Public static void main (string [] args) throws exception { String s = textfile.read ("thereplacements.java); // Match The Specially-Comment Block of Text Above: Matcher minput = Pattern.Compile ("///*! (.*)! /////", pattern.dotall) .matcher (s); IF (MINput.Find ()) s = minput.group (1); // Captured by Parentheses // Replace Two or more Spaces with a single space: s = s.replaceAll ("{2,}", ""); // Replace One or More Spaces at the beginning of each // Line with no space: Must Enable Multiline Mode: s = s.ReplaceAll ("(? M) ^ ", ""); System.out.println (s); S = S.Replacefirst ("[Aeiou]", "(Vowel1)"); StringBuffer SBUF = New StringBuffer (); Pattern P = Pattern.Compile ("[Aeiou]"); Matcher m = p.matcher (s); // process the find information as you // perform the replacements: While (m.find ()) M.AppendReplacement (SBUF, M.Group (). TouPpercase ()); // Put in the remainder of the text: M.Appendtail (SBUF); System.out.println (SBUF); Monitor.expect (new string "{ "Here's A Block of Text To Use as Input To", "THE REGAL EXPRESSION MATCHER. Note That We'll", "Firstract The Block of Text By Looking For", "THE SPECIAL DELIMITERS, THEN Process the", "Extracted Block.", "H (Vowel1) Re's a block of text to use as infut to", "THE REGAL EXPRESSION MATCHER. Note That We'll", "Firstract The Block of Text By Looking For", "THE SPECIAL DELIMITERS, THEN Process the", Extracted Block. " }); } } ///: ~ We use the TextFile.Read () method described earlier to open and read files. The function of MINPUT is the text between '/ *!' and '! * /' (note the parentheses of the group). Next, we replace all more than two consecutive spaces into one, and remove the spaces starting at all walks (in order to make this regular expression to all the lines, not just the first line, must be enabled Multi-line mode). Both operations use string replaceAll () (here more convenient). Note that because each replace is only once, there is no additional overhead in addition to the precompiled PATTERN. Replacefirst () only replaces the first substring. In addition, ReplaceFirst () and replaceall () can only be replaced with constant (Literal), so if you have some operations at a time, they are unable to force. When you encounter this, you have to use appendreplacement (), which will write how much code you want to write when you replace it. In the above program, the process of creating SBUF is to choose the group to process, that is, use the regular expression to put the vowel letters, and then replace it into a capital process. Usually you have to call appendtail () after completing all the replacement, but if you want to imitate the effect of ReplaceFirst (or "Replace N"), you can only replace AppendTail (). It will put all the rest in the SBUF. You can also use "$ g" to reference the captured Group in the replacement parameter of the appendreplacement (), where 'g' represents the number of Group. However, this is prepared for some relatively simple operation, so its effect cannot be compared to the above procedures. RESET () In addition, you can also use the reset () method to give an existing Matcher object with a new Charsequence. //: C12: RESETTING.JAVA Import java.util.regex. *; Import java.io. *; Import com.bruceeckel.simpletest. *; Public class recsetting { Private static test monitor = new test (); Public static void main (string [] args) throws exception { Matcher M = Pattern.Compile ("[frb] [aiu] [gx]") .matcher ("FIX THE RUG WITH BAGS"); While (m.find ()) System.out.println (M.Group ()); M.Reset ("FIX THE RIG WITH RAGS"); While (m.find ()) System.out.println (M.Group ()); Monitor.expect (new string "{ "fix", "rug", "BAG", "fix", "rig", "rag" }); } } ///: ~ If you do not give parameters, reset () will set Matcher to the beginning of the current string. Regular expression and Java I / O So far, you see an example of processing a static string with a regular expression. Let's demonstrate how to scan files with regular expressions and find a matching string. By UNIX GREP inspiration, I wrote a JGRep.java, it requires two parameters: file name, and regular expressions that match characters. It will print the line number of the matching of this regular expression and the line number of its belongs. //: c12: jgrep.java // a Very Simple Version of The "grep" program. // {args: jgrep.java "// b [SSCT] // w "} Import java.io. *; Import java.util.regex. *; Import java.util. *; Import com.bruceeckel.util. *; Public class jgrep { Public static void main (string [] args) throws exception {if (args.length <2) { System.out.println ("USAGE: Java Jgrep File Regex); System.exit (0); } Pattern P = Pattern.Compile (Args [1]); // Iterate Through The Lines of the Input File: Listiterator it = new textfile (args [0]). Listiterator (); While (it.hasnext ()) { Matcher M = p.matcher (String) it.next ()); While (m.find ()) System.out.println (it.nextIndex () ":" M.Group () ":" m.Start ()); } } } ///: ~ The file is opened with TextFile (the first half of this chapter). Since TextFile will put the lines of the file in ArrayList, and we have extracted a Listiterator, so we can move freely in each line of the file (both can be reusable beforewards). Every line will have a Matcher and then scan with a Find (). Note that we use the listiterator.nextindex () tracking line number. The test parameters are JGRep.java and the words starting with [SSCT]. Do you still need StringTokenizer? Seeing the regular expression can provide such a powerful feature, you may doubt, is it necessary to have the original StringTokenizer. Before JDK 1.4, you want to divide the string, only StringTokenizer. But now, after the regular expression, it can do a cleaner. //: C12: ReplacingStringTokenizer.java Import java.util.regex. *; Import com.bruceeckel.simpletest. *; Import java.util. *; Public class replacingstringtokenizer { Private static test monitor = new test (); Public static void main (String [] args) { String infut = "But I'm not dead yet! I feel happy!"; StringTokenizer Stoke = New StringTokenizer (INPUT); While (stoke.hasmorelements ()) System.out.println (stoke.nextToken ()); System.out.println (Arrays.aslist (Input.Split (")))))); Monitor.expect (new string "{ "But", "I'm", "not", "dead", "yet!", "I", "feel", "Happy!", [But, I'm, Not, Dead, Yet !, I, Feel, Happy!] " }); } } ///: ~ With a regular expression, you can use more complex patterns to split strings - If you give StringTokenizer, things will be much more trouble. I can have a very grasping, and the regular expression can replace StringTokenizer. To learn a regular expression, it is recommended that you see Mastering Regular Expression, 2nd Edition, author Jeffrey E. F. Friedl (O'Reilly, 2002). to sum up Java's I / O stream library should meet your basic needs: You can use it to read the write console, file, memory, and even the Internet. You can also use inheritance to create new input and output types. You can even use Java to automatically call the TOString () method of the object (only "Auto Type Conversion" in Java), to make a simple extension to the object to be passed by redefining this method. But Java's I / O stream library and its documents have left some shortcomings. For example, you open a file to write something, but this file is already, this will be overwritten. At this time, you can have an exception. It seems that Java is to use the file object to determine if the file exists because if you use FileoutPutStream or FileWrit, the file will be overwritten. I have a relatively contradictory evaluation of I / O stream libraries; it can do a lot of things, and have achieved cross-platform. But if you don't understand the Decorator mode, you will feel that this design is too difficult to understand, so, whether it is a teacher or a student, it has more flowers. In addition, this class library is incomplete, otherwise I also don't need to write textfile. In addition, it does not provide the function of formatting output, and other languages have provided this feature. However, once you truly understand the Decorator mode, you can feel the benefits of this design when you start flexible use of this class library. At this time, I will not write a few lines of code. If you feel that you don't want to be thirst (this chapter is just a introduction, you can't want to face it), you can go to the Java I / O (O'Reilly, 1999) written by Elliotte Rusty Harold. This book is deeper.