Java 字符流操作

     上篇文章Java 字节流操作介绍了java中基本的字节流操作,但是我们常常对于字符操作,如果使用字节流来实现输入输出就显得麻烦,我们可以使用字符流来实现对我们看得见的字符char进行操作,主要内容如下:

  • 基本流(Reader/Writer)
  • 转换流(InputStreamReader/OutputStreamEWriter)
  • 文件字符流(FileReader/FileWriter)
  • 字符数组流(charArrayReader/charArrayWriter)
  • 缓冲字符流(BufferedReader/BufferedWriter)
  • 装饰类(PrintWriter) 一、基本流      字节流的基本流是InputStream/OutputStream,这里的字符流的基本流是Reader/Writer,他们都是抽象类,想要实现更加复杂的操作就必须要子类来扩充。他们内部主要的就是read和write方法,实现单个字符及字符数组的读取的写入。此处就不再列出,我们将会从他们的子类中看看这些方法的实现。 二、转换流      InputStreamReader和OutputStreamWriter这两个类型流,在整个字符流中是十分重要的流,他们实现了和字节流的转换。先看看InputStreamReader:
private final StreamDecoder sd;

public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String charsetName)
public InputStreamReader(InputStream in, Charset cs)
public InputStreamReader(InputStream in, CharsetDecoder dec)

public int read() throws IOException {
        return sd.read();
    }
public int read(char cbuf[], int offset, int length) throws IOException {
        return sd.read(cbuf, offset, length);
    }

          首先定义了一个StreamDecoder 类型的常量(这是一个十分重要的成员),一堆构造方法通过不同的方式指定了外部传入的InputStream类型的参数和解码类型。我们看到,read方法中调用的是上述的sd常量(这是一个StreamDecoder类型的常量)的方法。这个StreamDecoder类实际上完成了将字节转换成char的操作。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{

        InputStreamReader inr = new InputStreamReader(new FileInputStream("hello.txt"));
        char[] chs = new char[100];
        inr.read(chs);
        System.out.println(chs);
        inr.close();
    }
}

          上述代码展示了如何从文件中按照指定的解码方式读取出字符,OutputStreamWriter几乎是逆操作:

public void write(int c)
public void write(char cbuf[], int off, int len)
public void write(String str, int off, int len)

          可以写int,可以写char数组,还可以写字符串(实际上还是调用了getchars方法获取该字符串的内置char数组,然后调用写数组的方法)。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{

       OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("hello.txt"));
        ow.write("walker");
        ow.close();
    }
}
/*可以明显感知,对字符操作的简单直接*/

三、文件字符流           FileReader和FileWriter两个流,继承的是上述的两个转换流。内部的方法非常简单,只是几个构造方法而已。

public FileReader(String fileName) throws FileNotFoundException {
        super(new FileInputStream(fileName));
    }
public FileReader(File file) throws FileNotFoundException {
        super(new FileInputStream(file));
    }


public FileWriter(String fileName) throws IOException {
        super(new FileOutputStream(fileName));
    }
public FileWriter(String fileName, boolean append) throws IOException {
        super(new FileOutputStream(fileName, append));
    }
public FileWriter(File file) throws IOException {
        super(new FileOutputStream(file));
    }

          从源代码中可以看出来,这两个文件流完全依赖父类。自己基本没有扩展父类,使用的方法都是父类的。你可以通过传文件的路径或者构建File类作为构造参数传入。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{

        FileReader fr = new FileReader("hello.txt");
        char[] chars = new char[1024];
        fr.read(chars);
        System.out.println(chars);
    }
}

          一样可以达到读取字符的效果,实际上上述代码可以转换为:

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{

        InputStreamReader ins = new InputStreamReader(new FileInputStream("hello.txt"));
        char[] chars = new char[1024];
        ins.read(chars);
        System.out.println(chars);
    }
}
//因为FIleReader的内部还是通过super调用父类的构造方法

四、字符数组流           和之前介绍的字节数组流类似,都是为了能提高效率防止内存浪费而设计的。看看我们上面的一段代码:

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{

        FileReader fr = new FileReader("hello.txt");
        char[] chars = new char[1024];
        fr.read(chars);
        System.out.println(chars);
    }
}

          这段程序其实是不完善的,因为我们默认hello文件中的字符容量小于等于1024,那如果文件足够大,我们势必要创建更大的字符数组(这是一种浪费内存)。我们可以使用字符数组流来实现动态扩容,解决内存空间。上述代码可以改写:

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{

        FileReader fr = new FileReader("hello.txt");
        int x = 0;
        CharArrayWriter chw = new CharArrayWriter();
        while ((x = fr.read()) != -1){
            chw.write(x);
        }
        System.out.println(chw.toString());
        chw.close();
    }
}

          这样,即使文件再大,我们也不会浪费很多内存空间。至于StingReader和StringWriter两个流其实是类似的,因为String的本质是char数组, 所以他们必然也是有数组作为最基本的操作。 五、缓冲字符流           字符的缓冲流和字节的缓冲流是类似的。都是装饰流。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{

        BufferedReader bins = new BufferedReader(new FileReader("hello.txt"));
        BufferedWriter bws = new BufferedWriter(new FileWriter("hello.txt",true));
        int x;
        while ((x = bins.read()) != -1){
            System.out.println((char)x);
            bws.write(x);
        }
    }
}
//缓冲读和缓冲写

六、PrintWriter           这是一个继承与Writer的流,他是一个非常方便的类,可以直接指定文件名作为参数,可以指定编码类型,还支持自动缓冲技术,可以自动转换多种基本类型为字符串形式写入文件中。在我们日常使用写入文件时,可以优先考虑使用该类。

protected Writer out;
private final boolean autoFlush;
//构造方法
public PrintWriter (Writer out) {
        this(out, false);
    }
public PrintWriter(OutputStream out) {
        this(out, false);
    }
public PrintWriter(String fileName) throws FileNotFoundException {
        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
             false);
public PrintWriter(File file) throws FileNotFoundException {
        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
             false);
    }
//写入一个character    
public void write(int c) {
        try {
            synchronized (lock) {
                ensureOpen();
                out.write(c);
            }
        }
        catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }
        catch (IOException x) {
            trouble = true;
        }
    }
//写入一个字符串    
public void write(String s) {
        write(s, 0, s.length());
    }

//重载print方法
public void print(boolean b) {
        write(b ? "true" : "false");
    }
public void print(char c) {
        write(c);
    }
 
public void print(int i) {
        write(String.valueOf(i));
    }
    
public void println() {
        newLine();
    }
public void println(int x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }
public void println(String x) {
        synchronized (lock) {
            print(x);
            println();
        }
    }   

          上述代码中的print和println并非和我们的标准输出流(System.out.println)同义,这里的print表示写入到文件中。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{

        PrintWriter pw = new PrintWriter("hello.txt");
        pw.println('x');
        pw.close();
     }
}

          使用了PrintWriter写入到文件中,非常的简单方便,可以指定文件路径,File,OutputStream作为构造方法的形参。这一切的转换都封装了,自动提供缓冲流。这是一种比较好的输出流,在之后的使用中,如果遇到输出到文件,应该优先考虑PrintWriter。           本篇文章结束了,这两篇文章是我阅读书籍和博客,加上jdk源代码总结得来,如有错误,望大家指出!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

从 Java 开始进入 Kotlin的世界: From Java to Kotlin: JKotlinor从 Java 开始进入 Kotlin的世界: From Java to Kotlin: JKo

在前面的内容里,我们已经看到了Java与Kotlin的互操作的基本方式。为了更好的认识Java与Kotlin这两门语言,我们在这里给出一些基本功能,同时使用Ja...

1092
来自专栏Ryan Miao

dom4j的读写xml文件,读写xml字符串

百度了一些博客,大同小异,在选取jar包工具的时候大概看了下,大抵是jdom原始,dom4j优秀。于是做了些练习。 参考:http://www.cnblogs....

36613
来自专栏微信公众号:Java团长

Java中的十个"单行代码编程"(One Liner)

本文列举了十个使用一行代码即可独立完成(不依赖其他代码)的业务逻辑,主要依赖的是Java8中的Lambda和Stream等新特性以及try-with-resou...

1032
来自专栏Jaycekon

Stream-快速入门Stream编程

一、什么是流 Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator...

3296
来自专栏chenjx85的技术专栏

leetcode-824-Goat Latin(字符串的处理)

3097
来自专栏一个会写诗的程序员的博客

《Kotlin 程序设计》第十一章 Kotlin实现DSL

DSL 即 domain-specific languages,领域特定语言。和一般的编程语言不同,领域特定语言只能用于特定的领域中并且表现形式有限。领域特定语...

1232
来自专栏数据之美

java 中 16 进制 HEX 转换成字节码形式的 UTF-8

恩,又碰到个蛋疼的编码转换问题了:要把形如 \xE9\xBB 的字符串转成中文。。。 在python中我们直接 print "\xE9\xBB\x84" ...

2665
来自专栏Java帮帮-微信公众号-技术文章全总结

java读取xml文件

xml文件:   Xml代码   <?xml version=”1.0” encoding=”GB2312”?>   <RESULT>   <VALUE>...

4588
来自专栏一个会写诗的程序员的博客

《Kotlin极简教程》第五章 Kotlin面向对象编程(OOP)一个OOP版本的HelloWorld构造函数传参Data Class定义接口&实现之写pojo bean定一个Rectangle对象封

We frequently create a class to do nothing but hold data. In such a class some s...

2334
来自专栏一个会写诗的程序员的博客

《Kotin 极简教程》第10章 Kotlin与Java互操作

在前面的章节中,我们已经学习了Kotlin的基础语法、类型系统、泛型与集合类、面向对象与函数式编程等主题,在上一章中我们还看到了Kotlin提供的轻量级并发编程...

2482

扫码关注云+社区

领取腾讯云代金券