原文链接https://www.codeliu.com/java/266.html
上一篇文章中讲了Java IO的字节流,这次同样的,先把整张图搬上来
Java IO整理总结之字符流_Java学习之旅

字符流的类相对字节流来说,没有这么多,但同样重要。

**

字符流

**
一.Reader
Java IO整理总结之字符流_IO_02

1.Reader

构造方法

Reader() 创建一个新的字符流 reader,其重要部分将同步其自身的 reader。

Reader(Object lock) 创建一个新的字符流 reader,其重要部分将同步给定的对象。

其他方法

void close() 关闭该流并释放与之关联的所有资源。

int read() 读取单个字符

int read(char[] cbuf) 将字符读入数组。

int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。

int read(CharBuffer target) 试图将字符读入指定的字符缓冲区。

boolean ready() 判断是否准备读取此流。

void reset() 重置该流

long skip(long n) 跳过字符

2.BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

构造方法

BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。

BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。

其他方法

String readLine() 读取一个文本行,不读取换行

3.CharArrayReader

此类实现一个可用作字符输入流的字符缓冲区。

构造方法

CharArrayReader(char[] buf) 根据指定的 char 数组创建一个 CharArrayReader

CharArrayReader(char[] buf, int off, int len) 根据指定的 char 数组创建一个 CharArrayReader。

4.FilterReader

用于读取已过滤的字符流的抽象类。抽象类 FilterReader 自身提供了一些将所有请求传递给所包含的流的默认方法。FilterReader 的子类应重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。

构造方法

FilterReader(Reader in) 创建一个新的 filtered reader。

5.InputStreamReader

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

构造方法

InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。

InputStreamReader(InputStream in, Charset cs) 创建使用给定字符集的 InputStreamReader。

InputStreamReader(InputStream in, CharsetDecoder dec) 创建使用给定字符集解码器的 InputStreamReader。

InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。

6.PipedReader

传送的字符输入流。

构造方法

PipedReader() 创建尚未连接的 PipedReader。

PipedReader(int size) 创建一个尚未连接的 PipedReader,并对管道缓冲区使用指定的管道大小。

PipedReader(PipedWriter src) 创建连接到传送 writer src 的 PipedReader。

PipedReader(PipedWriter src, int pipeSize) 创建一个 PipedReader,使其连接到管道 writer src,并对管道缓冲区使用指定的管道大小。

7.StringReader

其源为一个字符串的字符流。

构造方法

StringReader(String s) 创建一个新字符串 reader。

二.Writer
Java IO整理总结之字符流_字符流_03

1.BufferedWriter

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

构造方法

BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。

BufferedWriter(Writer out, int sz) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

其他方法

void close() 关闭此流,但要先刷新它

void flush() 刷新该流的缓冲区

void newLine() 写入一个行分隔符

void write(char[] buf, int off, int len) 写入字符数组的某一部分

void write(int c) 写入单个字符

void write(String s, int off, int len) 写入字符串的某一部分

2.CharArrayWriter

此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray() 和 toString() 获取数据。

构造方法

CharArrayWriter() 创建一个新的CharArrayWriter

CharArrayWriter(int size) 创建一个具有指定初始大小的新 CharArrayWriter。

其他方法

CharArrayWriter append(char c) 将指定字符添加到此 writer。

CharArrayWriter append(CharSequence csq) 将指定的字符序列添加到此 writer。

CharArrayWriter append(CharSequence csq, int start, int end) 将指定字符序列的子序列添加到此 writer。

int size() 返回缓冲区的当前大小

char[] toCharArray() 返回输入数据的副本

String toString() 将输入数据转换为字符串

void writeTo(Write out) 将缓冲区的内容写入另一字符流

3.FilterWriter

用于写入已过滤的字符流的抽象类。抽象类 FilterWriter 自身提供了一些将所有请求传递给所包含的流的默认方法。FilterWriter 的子类应重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。

构造方法

FilterWriter(Writer out) 创建一个新的 filtered writer。

4.OutputStreamWriter

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

构造方法

OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter。

OutputStreamWriter(OutputStream out, Charset cs) 创建使用给定字符集的 OutputStreamWriter。

OutputStreamWriter(OutputStream out, CharsetEncoder enc) 创建使用给定字符集编码器的 OutputStreamWriter。

OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter。

5.PipedWriter

传送的字符输出流。

构造方法

PipedWriter() 创建一个尚未连接到传送 reader 的传送 writer。

PipedWriter(PipedReader snk) 创建传送 writer,使其连接到指定的传送 reader

6.StringWriter

一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。

构造方法

StringWriter() 使用默认初始字符串缓冲区大小创建一个新字符串 writer。

StringWriter(int initialSize) 使用指定初始字符串缓冲区大小创建一个新字符串 writer。

其他方法

StringWriter append(char c) 将指定字符添加到此 writer。

StringWriter append(CharSequence csq) 将指定的字符序列添加到此 writer。

StringWriter append(CharSequence csq, int start, int end) 将指定字符序列的子序列添加到此 writer。

StringBuffer getBuffer() 返回该字符串缓冲区本身。

String toString() 以字符串的形式返回该缓冲区的当前值。

void write(String str) 写入一个字符串

下面我们来看看代码

/**
 * @author liu 
 * @version 创建时间:2018年3月5日 下午6:00:49 
 * 类说明 BufferedReader BufferedWriter PrintWriter 
 */
 public class BrAndBwOrPw { 
     public static void main(String[] args) throws IOException{ 
         BufferedReader br = new BufferedReader( new InputStreamReader(new FileInputStream("demo\\test.txt"))); 
         BufferedWriter bw = new BufferedWriter( new OutputStreamWriter(new FileOutputStream("demo\\test2.txt"))); 
         PrintWriter pw = new PrintWriter("demo\\test3.txt"); 
         String s; 
         while((s = br.readLine()) != null) { 
             // 不读取换行 
             //System.out.print(s);   
             System.out.println(s); 
             bw.write(s); 
             // 换行 
             bw.newLine(); 
             pw.println(s); 
         } 
         bw.flush(); 
         br.close();
         bw.close(); 
         pw.flush();
         pw.close(); 
     }
}
/**
 * @author liu 
 * @version 创建时间:2018年3月5日 下午5:47:06
 * 类说明 FileReader FileWriter 
 */
public class FrAndFw { 
    public static void main(String[] args) throws IOException{ 
        // 构造函数不能设置字符编码,默认gbk,如果读取其他类型的编码,会出现乱码 
        FileReader fr = new FileReader("demo\\test.txt"); 
        // 加true表示在后面追加 
        //FileWriter fw = new FileWriter("demo\\test1.txt", true); 
        FileWriter fw = new FileWriter("demo\\test1.txt"); 
        int b; 
        while((b = fr.read()) != -1) { 
            System.out.print((char)b); 
            fw.write(b); 
        } 
        // 记得刷新 
        fw.flush(); 
        fr.close(); 
        fw.close(); 
    }
}
/**
 * @author liu
 * @version 创建时间:2018年3月5日 下午4:48:15
 * 类说明 InputStreamReader OutputStreamReader 
 */
public class IsrAndOsrDemo { 
    public static void main(String[] args) throws IOException{ 
        FileInputStream in = new FileInputStream("demo\\test.txt"); 
        // 默认gbk编码,应使用项目具体要的编码格式 
        InputStreamReader isr = new InputStreamReader(in); 
        //InputStreamReader isr1 = new InputStreamReader(in, "utf-8"); 
        //FileOutputStream out = new FileOutputStream("demo\\test1.txt"); 
        //int b; 
        //while((b = isr.read()) != -1) { 
            //System.out.print((char)b); 
        //} 
        byte[] buf = new byte[8 * 1024]; 
        int c; 
        while((c = in.read(buf, 0, buf.length)) != -1) { 
            String s = new String(buf, 0, c); 
            System.out.print(s); 
        } 
    }
}

**

RandomAccessFile

**
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。

通常,如果此类中的所有读取例程在读取所需数量的字节之前已到达文件末尾,则抛出 EOFException(是一种 IOException)。如果由于某些原因无法读取任何字节,而不是在读取所需数量的字节之前已到达文件末尾,则抛出 IOException,而不是 EOFException。需要特别指出的是,如果流已被关闭,则可能抛出 IOException。

RandomAccessFile适用于由大小已知的记录组成的文件。

构造方法

RandomAccessFile(File file, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

RandomAccessFile(String name, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。

其他方法

long getFilePointer() 返回此文件中的当前偏移量

long length() 返回此文件的长度

int read() 从此文件中读取一个数据字节

int read(byte[] b) 将最多 b.length 个数据字节从此文件读入 byte 数组。

int read(byte[] b, int off, int len) 将最多 len 个数据字节从此文件读入 byte 数组。

boolean readBoolean() 从此文件读取一个boolean

。。。。包括int readInt() 之类的方法,具体看手册

void seek(long pos) 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。

void setLength(long newLength) 设置此文件的长度。

void write(byte[] b) 将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。

void write(int b) 向此文件写入指定的字节

void write(byte[] b , int off, int len) 将 len 个字节从指定 byte 数组写入到此文件,并从偏移量 off 处开始。

void writeBoolean(boolean v) 按单字节值将 boolean 写入该文件

。。。。包括void writeInt() 之类的方法,具体看手册

下面看看代码

/**
 * @author liu
 * @version 创建时间:2018年3月2日 下午3:48:44
 * RandomAccessFile类的使用 
 */
public class RafDemo { 
    public static void main(String[] args) throws IOException { 
        // 相对路径 
        File demo = new File("demo"); 
        if(!demo.exists()) { 
            demo.mkdir(); 
        } 
        // demo文件夹下的test.txt 
        File file = new File(demo, "test.txt"); 
        if(!file.exists()) { 
            file.createNewFile(); 
        } 
        RandomAccessFile raf = new RandomAccessFile(file, "rw"); 
        // 返回当前指针的位置 
        System.out.println(raf.getFilePointer()); 
        // 一次只能写一个字节,所有写入A的后八位 
        raf.write('A'); 
        System.out.println(raf.getFilePointer()); 
        raf.write('B'); 
        int x = 0x7fffffff; 
        // 写入高8位 
        raf.write(x >>> 24);  
        raf.write(x >>> 16); 
        raf.write(x >>> 8); 
        raf.write(x); 
        System.out.println(raf.getFilePointer()); 
        // 直接写入一个整数 
        raf.writeInt(x); 
        String s = "中"; 
        byte[] gbk = s.getBytes("gbk"); 
        raf.write(gbk); 
        System.out.println(raf.length()); 
        // 读文件,必须把指针移到头部 
        raf.seek(0); 
        // 一次性读取,raf.length返回的是long类型 
        byte[] readF = new byte[(int) raf.length()]; 
        raf.read(readF); 
        System.out.println(Arrays.toString(readF)); 
        for(byte b:readF) { 
            System.out.print(Integer.toHexString(b) + "  "); 
        } 
        // 记得关闭文件 
        raf.close(); 
    }
}

**

总结

**
Java IO 的一般使用原则 :

一、按数据来源(去向)分类:

1 、是文件: FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 )

2 、是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 字节流 )

3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符流 )

4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 字节流 )StringReader, StringWriter( 字符流 )

5 、网络数据流: InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 )

二、按是否格式化输出分:

1 、要格式化输出: PrintStream, PrintWriter

三、按是否要缓冲分:

1 、要缓冲: BufferedInputStream, BufferedOutputStream,( 字节流 ) BufferedReader, BufferedWriter( 字符流 )

四、按数据格式分:

1 、二进制格式(只要不能确定是纯文本的) : InputStream, OutputStream 及其所有带 Stream 结束的子类

2 、纯文本格式(含纯英文与汉字或其他编码方式); Reader, Writer 及其所有带 Reader, Writer 的子类

五、按输入输出分:

1 、输入: Reader, InputStream 类型的子类

2 、输出: Writer, OutputStream 类型的子类

六、特殊需要:

1 、从 Stream 到 Reader,Writer 的转换类: InputStreamReader, OutputStreamWriter

2 、对象输入输出: ObjectInputStream, ObjectOutputStream

3 、进程间通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter

4 、合并输入: SequenceInputStream

5 、更特殊的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader

决定使用哪个类以及它的构造进程的一般准则如下(不考虑特殊需要):

首先,考虑最原始的数据格式是什么: 原则四

第二,是输入还是输出:原则五

第三,是否需要转换流:原则六第 1 点

第四,数据来源(去向)是什么:原则一

第五,是否要缓冲:原则三 (特别注明:一定要注意的是 readLine() 是否有定义,有什么比 read, write 更特殊的输入或输出方法)

第六,是否要格式化输出:原则二