Java字符流

1- 介绍

在前面的指导性文章,我们介绍了输入输出二进制流。学习的输入输出字符流之前你需要去了解它。也可以看看这里:

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.
// Constructor
public 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 List
Apricots
Barbados Cherries
Bitter Melon
Cherimoya
Honeydew
Jackfruit
Limes
Lychee
Mango
Oranges
Pineapple
Strawberries
  • 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 stream
public 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");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值