Java字符流

来源:互联网 发布:进职称网络教育学历 编辑:程序博客网 时间:2024/05/17 07:49

1- 介绍

在前面的指导性文章,我们介绍了输入输出二进制流。学习的输入输出字符流之前你需要去了解它。也可以看看这里:
  • http://www.yiibai.com/java/java-io-tutorial-binary-streams.html

2- 二进制流和字符流之间的差异

二进制流,每一个读出(相当于8位)的一个字节。

同时,字符流读取每个读数又将一个字符。它是依赖于编码(UTF-8,UTF-16,...)的类型,以决定在每个读数反过来这是1字节,2字节,或3个字节的字节数。让我们来看看下面的图示说明:

UTF-16:

这是日本文字。如果它被存储在一个以UTF-16编码的文件,在硬盘驱动器上的字节类似于图片:
  • 两个首字节(254,255)的意思是通知一系列的UTF-16编码的开始
  • 接下来是由2个字节编码的字符
    • 例如,J字符被编码用2个字节(0和74)
    • P字符用2字节(0和80)编码
    • .....
  • 使用UTF-16编码读取文件时,会排除两个首字节并读取两个连续字节

UTF-8:

上述日本文本记录使用UTF-8编码是有所不同的。可以看到,字节存储在硬盘驱动器:
  • 对于正常(latin)的拉丁字符,只需要1个字节来存储。
    • 例如,它需要1个字节来存储一个字符(74)
    • 它需要1个字节来存储P字符(80)
  • 这可能需要2个字节或3个字节来存储其它字符
  • 在读取规则,它有标准的UTF-8字符的**表
    • 读取第一字节,如果是<=127,它是一个ASCII字符
    • 相反,如果是>127,它将需要继续读第二个字节,并考虑这两个字节是否为1个字符或不是,就可以知道字符是什么。
    • 如果在前面的步骤中,并没有一个字符,它将进行读取第三个字节并全部加入到一个字符。

综上所述,当使用任何编码保存文档,需要用对应的编码来读取,否则读取输出将是错误的。

3- 字符流的概述

这是字符流的类层次结构:

4- java.io.Reader类

Reader是一个抽象类。读取字符流是从这个类扩展的。
创建一个文件 test_reader.txt 来使用 Reader 的例子:
  • HelloReader.java
package com.yiibai.tutorial.javaio.readerwriter;import java.io.FileReader;import java.io.IOException;import java.io.Reader;public class HelloReader {   public static void main(String[] args) throws IOException {             // Character stream, read a file       // FileReader read file with default encoding of machine running this code.       Reader r = new FileReader("test_reader.txt");       int i = -1;       // Read one character (return int)       while ((i = r.read()) != -1) {           // Cast to char.           System.out.println((char) i);       }       r.close();   }}
运行例子结果:
下一个例子是依次读取了许多字符,它们被分配一个临时的数组中。这有助于提高相对于依次读取每个字符的程序效率。
  • HelloReader2.java
package com.yiibai.tutorial.javaio.readerwriter;import java.io.FileReader;import java.io.IOException;import java.io.Reader;// This example, read multi characters in once.public class HelloReader2 {    public static void main(String[] args) throws IOException {              // Character stream, read a file        // FileReader read file with default encoding of machine running this code.                Reader r = new FileReader("test_reader.txt");        // Create temporary array of characters.        char[] temp = new char[10];        int i = -1;             // Method read(char[]):        // Reads characters into an array.        // The number of characters read.        // or -1 if the end of the stream has been reached        while ((i = r.read(temp)) != -1) {            String s = new String(temp, 0, i);            System.out.println(s);        }        r.close();    }}

5- java.io.Writer类

Writer类是一个抽象类。所有输出字符流都是从这个类扩展的。
  • HelloWriter.java
package com.yiibai.tutorial.javaio.readerwriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.Writer;public class HelloWriter {    public static void main(String[] args) throws IOException {        File dir = new File("C:/test");        // Create directories, if it not exists.        dir.mkdirs();        // Create character stream to write to file.        // Using default encoding of machine running this code.             Writer w = new FileWriter("C:/test/test_writer.txt");        // Array of characters.        char[] chars = new char[] { 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'r',                'i', 't', 'e', 'r' };        // Write characters to stream.        for (int i = 0; i < chars.length; i++) {            char ch = chars[i];            // Cast to int.            int j = (int) ch;            // Write to stream.            w.write(j);        }        // Close stream,        w.close();    }}
运行示例的结果:
下一个例子是在同一时间向流写入多个字符。具体来说,我们写入字符流的一个数组。这有助于提高相对于依次写入每个字符的程序的效率。
  • HelloWriter2.java
package com.yiibai.tutorial.javaio.readerwriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.Writer;public class HelloWriter2 {        public static void main(String[] args) throws IOException {        File dir = new File("C:/test");        // Create directories, if it not exists.        dir.mkdirs();        // Create character stream to write file.        Writer w = new FileWriter("C:/test/test_writer2.txt");        char[] chars = new char[] { 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'r',                'i', 't', 'e', 'r' };        // Write characters to stream.        w.write(chars);               // Typically Java cache used to store data (in memory)        // when the buffer is full, it pushes the data to the file.        // You can actively push data into the file.        w.flush();                // Write 'new line' character to stream.s        w.write('\n');        String s = "FileWriter";        // Write a String to stream.        w.write(s );                    // Close stream.        // It will push the data in buffer to the file, and close stream.        // Finish write file.        w.close();    }}
运行示例的结果:

6- 二进制流如何转换成字符流?

当我们有一个二进制流。并且希望将它转换成字符流,怎么做?

在上面的例子中,我们习惯于使用Reader 和 Writer。下一个例子显示读取和写入到流中,要有明确的编码规定。
创建一个文件:test_utf8.txt

  • test_utf8.txt
JP日本-八洲
当保存,eclipse会问你要保存成为什么类型的编码。选择UTF-8?

  • InputStreamReaderExample.java
package com.yiibai.tutorial.javaio;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.Reader;public class InputStreamReaderExample {    public static void main(String[] args) throws IOException {        // Create binary stream, read a file.        InputStream in = new FileInputStream("test_utf8.txt");        // Create character stream from binary stream.        // encoding UTF-8        Reader reader = new InputStreamReader(in, "UTF-8");        int i = 0;        // Read turn each character        while ((i = reader.read()) != -1) {            // cast int to char, and print to the Console            System.out.println((char) i + " " + i);        }        reader.close();    }}
运行示例的结果如下:

下一个例子是使用UTF-8编码写入到文件
  • OutputStreamWriterExample.java
package com.yiibai.tutorial.javaio;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.Writer;public class OutputStreamWriterExample {    public static void main(String[] args) throws IOException {        File dir = new File("C:/test");        // Create directories if it not exists.        dir.mkdirs();        // Create binary output stream, write to a file.        OutputStream out = new FileOutputStream("C:/test/test_write_utf8.txt");        // Create character stream from binary stream.        // encoding UTF-8.        Writer writer = new OutputStreamWriter(out, "UTF-8");        String s = "JP日本-八洲";        writer.write(s);        writer.close();    }}
运行示例的结果:

7- java.io.BufferedReader类


// If you want to read each line of data of a text file. BufferedReader is a good choice.// As a direct subclass of the Reader class.// Constructorpublic BufferedReader(Reader in);// Create BufferedBuffer object, wrap Reader object.// Utility methods of BufferedReader :// Read a line.public String readLine();// The code example:// Create stream read a file.Reader r=new FileReader("C:/test.txt");BufferedReader br=new BufferedReader(r);// The code example:InputStream in = new FileInputStream("C:/test.txt");Reader r = new InputStreamReader(in, "UTF-8");BufferReader br = new BufferedReader(r);
如果想要读的文本文件的每一行数据。 BufferedReader是一个不错的选择。

  • test_multi_lines.txt
## Fruit ListApricotsBarbados CherriesBitter MelonCherimoyaHoneydewJackfruitLimesLycheeMangoOrangesPineappleStrawberries
  • BufferedReaderExample.java
package com.yiibai.tutorial.javaio.buffered;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.Reader;public class BufferedReaderExample {    public static void main(String[] args) throws IOException {        InputStream in = new FileInputStream("test_multi_lines.txt");        Reader reader = new InputStreamReader(in, "UTF-8");        BufferedReader br = new BufferedReader(reader);        String s = null;        int i = 0;               // Read each line of data        // If returns null means ending stream.        while ((s = br.readLine()) != null) {            i++;            System.out.println(i + " : " + s);        }        br.close();    }}
运行示例的结果如下:

8- java.io.BufferedWriter类

// BufferedWriter class is a direct subclass of Writer.// Constructor// Create BufferedWriter object, wrap other Writer object.public BufferedWriter(Writer out);// Methods of BufferedWriter.// Equivalent to calling write ('\ n');public String newLine();// The code example:// Create character stream to write file.Writer w=new FileWriter("C:/jhelp/test_bufferedWriter.txt");// Create BufferedWriter wrap 'w'BufferedWriter bw=new BufferedWriter(w);bw.write("Hello..");// Print 'new line'bw.newLine();

9- java.io.FilterReader类


FilterReader是有选择地从字符流读取所需的字符。例如,读取包含HTML标记的文本文件,并在标签中排除字符。你需编写 FileReader 的子类,然后再使用子类。我们不能直接使用 FileReader,因为它是一个抽象类。
例如,流读取过滤字符,读取HTML不过在标签中忽略字符。
例如,输入  "<h1>Hello</h1>" ==> 输出:  "Hello".
  • RemoveHTMLReader.java
package com.yiibai.tutorial.javaio.filter;import java.io.FilterReader;import java.io.IOException;import java.io.Reader;public class RemoveHTMLReader extends FilterReader {  // Used to remember whether we are "inside" a tag  boolean intag = false;  public RemoveHTMLReader(Reader in) {      super(in);  }  /**   * This is the implementation of the no-op read() method of FilterReader. It   * calls in.read() to get a buffer full of characters, then strips out the   * HTML tags. (in is a protected field of the superclass).   */  @Override  public int read(char[] buf, int from, int len) throws IOException {      // how many characters have been read      int charCount = 0;      // Loop, because we might read a bunch of characters, then strip them      // all out, leaving us with zero characters to return.      while (charCount == 0) {          // Read characters          charCount = super.read(buf, from, len);          if (charCount == -1) {              // Check for EOF and handle it.              return -1;          }          // Loop through the characters we read, stripping out HTML tags.          // Characters not in tags are copied over previous tags          // Index of last non-HTML char          int last = from;          for (int i = from; i < from + charCount; i++) {              // If not in an HTML tag              if (!intag) {                  if (buf[i] == '<') {                      // Check for tag start                      intag = true;                  } else {                      // and copy the character                      buf[last++] = buf[i];                  }              } else if (buf[i] == '>') {                  // check for end of tag                  intag = false;              }          }          // Figure out how many characters remain          charCount = last - from;      }      // Then return that number.      return charCount;  }  /**   * This is another no-op read() method we have to implement. We implement it   * in terms of the method above. Our superclass implements the remaining   * read() methods in terms of these two.   */  @Override  public int read() throws IOException {      char[] buf = new char[1];      int result = read(buf, 0, 1);      if (result == -1) {          return -1;      } else {          return (int) buf[0];      }  }}
  • RemoveHTMLReaderTest.java
package com.yiibai.tutorial.javaio.filter;import java.io.BufferedReader;import java.io.IOException;import java.io.Reader;import java.io.StringReader;public class RemoveHTMLReaderTest {    public static void main(String[] args) throws IOException {                // Create Reader object from StringReader constructor.        Reader in = new StringReader("<h1>Hello \n <b>World</b><h1>");        RemoveHTMLReader filterReader = new RemoveHTMLReader(in);        BufferedReader br = new BufferedReader(filterReader);        String s = null;        while ((s = br.readLine()) != null) {            System.out.println(s);        }        br.close();    }}
运行示例的结果:

10- java.io.FilterWriter类


FilterWriter写入字符流,选择写入所需的的字符。通常情况下,你所编写的FilterWriter子类,可以覆盖它的方法,并以你的方式写入数据流中。
下面的例子演示了数据写入流中时如何转换。它可以被认为这是加密的简单方式。
  • Rot13.java
package com.yiibai.tutorial.javaio.filter;public class Rot13 {        /**     * <pre>     *   a ==> n     *   b ==> o     *   c ==> p     *   d ==> q     *   e ==> r     *   ...     *   y ==> l     *   z ==> m     * </pre>     */    public static int rotate(int inChar) {        int outChar;                if (inChar >= (int) 'a' && inChar <= (int) 'z') {            outChar = (((inChar - 'a') + 13) % 26) + 'a';        } else if (inChar >= (int) 'A' && inChar <= (int) 'Z') {            outChar = (((inChar - 'A') + 13) % 26) + 'A';        } else {            outChar = inChar;        }        return outChar;    }        // Test    public static void main(String[] args)  {        for(char ch='a'; ch<='z';ch++ ) {            char m= (char)rotate(ch);            System.out.println("ch="+ch+" ==> "+ m);            }                   }} 
  • RotateWriter.java
package com.yiibai.tutorial.javaio.filter;import java.io.FilterWriter;import java.io.IOException;import java.io.Writer;public class RotateWriter extends FilterWriter {   // must provide constructor to extend FilterWriter;   // objective is to allow constructing a filter stream   // connecting to any character output stream (class Writer)   public RotateWriter(Writer out) {       super(out);   }   // override one or more write methods to perform filtering   // (we override both to be safe)   @Override   public void write(int outChar) throws IOException {       super.write(Rot13.rotate(outChar));   }   @Override   public void write(char[] cbuf, int offset, int length) throws IOException {       char[] tempbuf = new char[length];       for (int i = 0; i < length; i++) {           tempbuf[i] = (char) Rot13.rotate(cbuf[offset + i]);       }       super.write(tempbuf, 0, length);   }}
  • RotateWriterTest.java
package com.yiibai.tutorial.javaio.filter;import java.io.IOException;import java.io.StringWriter;import java.io.Writer;public class RotateWriterTest {        public static void main(String[] args) throws IOException  {        String s="abcdef";                Writer writer= new StringWriter();                RotateWriter rw= new RotateWriter(writer);        rw.write(s.toCharArray(),0,s.length());                rw.close();                String rotateString = writer.toString();        System.out.println("rotateString="+ rotateString);    }} 
运行示例的结果如下:

11- java.util.PushbackReader类

PushbackReader类允许一个或多个字符返回到输入流。 这使您可以在输入流中向前查看。下面是它的两个构造函数:
public PushbackReader(Reader inputStream)public PushbackReader(Reader inputStream, int bufSize)
还有一些其它方法:
// Pushes back a single character by copying it to// the front of the pushback buffer.// (like - move the cursor back one position)**public void unread(int c) throws IOException
  • PushbackReaderDemo.java
package com.yiibai.tutorial.javaio.pushback;import java.io.CharArrayReader;import java.io.IOException;import java.io.PushbackReader;class PushbackReaderDemo {    public static void main(String args[]) throws IOException {        String s = "if (a == 4) a = 0;\\n";        char buf[] = new char[s.length()];        s.getChars(0, s.length(), buf, 0);        CharArrayReader in = new CharArrayReader(buf);        PushbackReader f = new PushbackReader(in);        int c;        while ((c = f.read()) != -1) {            switch (c) {            // Found character '='            case '=':                // Read next character, (after found '-')                if ((c = f.read()) == '=') {                    System.out.print(".eq.");                }                // If next character different from '='.                else {                    System.out.print("<-");                    // Pushes back a single character by copying it to                    // the front of the pushback buffer.                    // (like - move the cursor back one position)                    f.unread(c);                }                break;            default:                System.out.print((char) c);                break;            }        }    }}
运行示例的结果:

12- java.io.PrintWriter类


// Constructor// PrintWriter is direct subclass of Writer .// It can wrap a character output stream (Writer) or binary output stream (OutputStream), ..public PrintWriter(Writer out) // Wrap a character streampublic PrintWriter(Writer out,boolean autoFlush)public PrintWriter(OutputStream out) // Wrap binary stream.public PrintWriter(OutputStream out,boolean autoFlush)public PrintWriter(String fileName)...// Some methods:public void println(String s)public void print(char ch)
  • StackTraceToFile.java
package com.yiibai.tutorial.javaio.printwriter;import java.io.File;import java.io.FileWriter;import java.io.PrintWriter;import java.io.Writer;public class StackTraceToFile {    public static void main(String[] args) {        try {                       // Do something here            // Exception, error divided by 0.            int i = 10 / 0;        } catch (Exception e) {            System.out.println("EXCEPTION ....");            try {                File dir = new File("C:/test");                // Create directories if it not exists.                dir.mkdirs();                // Create stream to write file.                Writer w = new FileWriter("C:/test/stackTrace.txt");                               // Create PrintWriter object wrap 'w'                // Data written to the PrintWriter will be pushed into 'w'.                PrintWriter pw = new PrintWriter(w);                                // Write 'stack trace' to 'pw'.                e.printStackTrace(pw);                System.out.println("Finish !");            } catch (Exception e1) {                System.out.println("Error:" + e);            }        }    }}
  • StackTraceToString.java
package com.yiibai.tutorial.javaio.printwriter;import java.io.PrintWriter;import java.io.StringWriter;public class StackTraceToString {    public static void main(String[] args) {        try {                       // Do something here            // Exception, error divided by 0.                        int i = 1000 / 0;        } catch (Exception e) {            System.out.println("EXCEPTION ....");            try {                StringWriter sw = new StringWriter();                               // Create PrintWriter object wrap 'sw'                // Data written to the PrintWriter will be pushed into 'sw'.                                PrintWriter pw = new PrintWriter(sw);                                // Write 'stack trace' to 'pw'.                e.printStackTrace(pw);                                StringBuffer sb = sw.getBuffer();                String s = sb.toString();                System.out.println("Exception String:");                System.out.println(s);            } catch (Exception e1) {                System.out.println("Error:" + e);            }        }    }}
运行示例的结果:

13- java.io.CharArrayReader类

  • CharArrayReaderDemo.java
package com.yiibai.tutorial.javaio.chararray;import java.io.CharArrayReader;import java.io.IOException;public class CharArrayReaderDemo {        public static void main(String args[]) throws IOException {                String tmp = "abcdefghijklmnopqrstuvwxyz";        int length = tmp.length();        char c[] = new char[length];        tmp.getChars(0, length, c, 0);                CharArrayReader input1 = new CharArrayReader(c);        CharArrayReader input2 = new CharArrayReader(c, 0, 5);                int i;        System.out.println("input1 is:");        while ((i = input1.read()) != -1) {            System.out.print((char) i);        }        System.out.println();        System.out.println("input2 is:");        while ((i = input2.read()) != -1) {            System.out.print((char) i);        }        System.out.println();    }}
运行示例的结果:

14- java.io.CharArrayWriter类

还有一些其它方法:
// Writes the contents of the buffer to another character stream.public void writeTo(Writer out) throws IOException
  • CharArrayWriterDemo.java
package com.yiibai.tutorial.javaio.chararray;import java.io.CharArrayWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;public class CharArrayWriterDemo {    public static void main(String args[]) throws IOException {        char c[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!' };        CharArrayWriter out = new CharArrayWriter();        out.write(c);        File dir = new File("C:/test");        dir.mkdirs();        FileWriter f1 = new FileWriter(new File("C:/test/a.txt"));        // File written successfully.        out.writeTo(f1);        FileWriter f2 = new FileWriter(new File("C:/test/b.txt"));        // File written successfully.        out.writeTo(f2);        f1.close();        f2.close();        // CharArrayWriter is closed.        out.close();        FileWriter f3 = new FileWriter(new File("C:/test/c.txt"));        // Write again to a file.        // No Exception from CharArrayWriter but no data will be written.        out.writeTo(f3);        System.out.println("Done");    }}
0 0