上篇文章[Java 字节流操作](http://www.cnblogs.com/yangming1996/p/6549800.html)介绍了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源代码总结得来,如有错误,望大家指出!

Java 字符流操作的更多相关文章

  1. java字符流操作flush()方法及其注意事项

    java字符流操作flush()方法及其注意事项   flush()方法介绍 查阅文档可以发现,IO流中每一个类都实现了Closeable接口,它们进行资源操作之后都需要执行close()方法将流关闭 ...

  2. Java 字符流实现文件读写操作(FileReader-FileWriter)

    Java 字符流实现文件读写操作(FileReader-FileWriter) 备注:字符流效率高,但是没有字节流底层 字节流地址:http://pengyan5945.iteye.com/blog/ ...

  3. Java字符流和字节流对文件操作

    记得当初自己刚开始学习Java的时候,对Java的IO流这一块特别不明白,所以写了这篇随笔希望能对刚开始学习Java的人有所帮助,也方便以后自己查询.Java的IO流分为字符流(Reader,Writ ...

  4. java的IO操作:字节流与字符流操作

    流的概念 程序中的输入输出都是以流形式,流中保存的实际上都是字节文件. 字节流与字符流 字节流的操作: 1)输入:inputStream, 2)输出:outPutStream; 字符流的操作: 1)输 ...

  5. Java 字符流文件读写

    上篇文章,我们介绍了 Java 的文件字节流框架中的相关内容,而我们本篇文章将着重于文件字符流的相关内容. 首先需要明确一点的是,字节流处理文件的时候是基于字节的,而字符流处理文件则是基于一个个字符为 ...

  6. Java IO流操作汇总: inputStream 和 outputStream【转】

    我们在进行Android java 开发的时候,经常会遇到各种IO流操作.IO流操作一般分为两类:字符流和字节流.以“Reader”结尾都是字符流,操作的都是字符型的数据:以“Stream”结尾的都是 ...

  7. Java 文件流操作.

    一.概念 在Java中,文件的输入和输出是通过流(Stream)来实现的.一个流,必有源端和目的端,它们可以是计算机内存的某些区域,也可以是磁盘文件,甚至可以是 Internet 上的某个 URL.对 ...

  8. java字符流与字节流的区别是什么

    java中字符流与字节流的区别: 1.字节流操作的基本单元为字节:字符流操作的基本单元为Unicode码元. 2.字节流默认不使用缓冲区:字符流使用缓冲区. 3.字节流通常用于处理二进制数据,实际上它 ...

  9. 全面吃透JAVA Stream流操作,让代码更加的优雅

    全面吃透JAVA Stream流操作,让代码更加的优雅 在JAVA中,涉及到对数组.Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行 ...

随机推荐

  1. java7 invokedynamic命令深入研究

    在看java虚拟机字节码执行引擎的时候,里面提到了java虚拟机里调用方法的字节码指令有5种: invokestatic //调用静态方法 invokespecial //调用私有方法.实例构造器方法 ...

  2. iOS 图片压缩方法

    iOS 图片压缩方法 两种图片压缩方法 两种压缩图片的方法:压缩图片质量(Quality),压缩图片尺寸(Size). 压缩图片质量 NSData *data = UIImageJPEGReprese ...

  3. ubuntu 更新引导命令

    sudo update-grub 运行结果: Generating grub configuration file ...Warning: Setting GRUB_TIMEOUT to a non- ...

  4. 你真的了解如何将 Nginx 配置为Web服务器吗

    阅读之前,建议先阅读初识 Nginx. 之后,我们来了解一下 Nginx 配置. 抽象来说,将 Nginx 配置为 Web 服务器就是定义处理哪些 URLS 和如何处理这些URLS 对应的请求.具体来 ...

  5. WPF DEV CellTemplateSelector(一个正确使用DevExpress CellTemplateSelector的Demo)

    说明 我在项目中根据需求需要用到WPF Dev CellTemplateSelector时,遇到不少坑.曾一度想要放弃使用模板转换器,但又心有不甘,终于在不断努力下,达到了需求的要求.所以写下来和大家 ...

  6. 使用jsCompress压缩混淆js代码的一些常见的问题和技巧

    不同的团队使用的js混淆器或压缩工具不一样,jsCompress是一款绿色的免费的js压缩工具,时代定制的UI团队推荐大家使用,不仅性能优越,而且操作非常人性化. 使用jsCompress.exe时, ...

  7. datagridview数据绑定操作数据库实现增删改查

    DataSet数据集,数据缓存在客户端内存中,支持断开式连接.DataGridView控件绑定DataSet时,它自动的改变的DS的行的状态,而且在做增删改查的时候,可以借助SqlCommandBui ...

  8. python3 UnicodeEncodeError: 'gbk' codec can't encode character '\uff70' in position 75267: illegal multibyte sequence

    当你爬出想要的数据了,却发现中文是乱码的时候?请你计算下你内心的阴影面积 ! 菊个栗子: #!/usr/bin/env python3# -*- coding: utf-8 -*-import ioi ...

  9. hashcode的一些了解

    1.hashcode的作用? hashcode代表对象的特征,在集合类中广泛的使用. 2.hashcode是如何生成的? 在普通的对象中,获得对象的内存的地址,经过一些算法,不同对象生成不同的hash ...

  10. HTML5 DOM扩展

    一.选择符 1. querySelector()方法:返回与该模式匹配的第一个元素 //取得body元素 var body = document.querySelector("body&qu ...