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");
}
}

110

被折叠的 条评论
为什么被折叠?



