上篇文章[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:
  1. private final StreamDecoder sd;
  2. public InputStreamReader(InputStream in)
  3. public InputStreamReader(InputStream in, String charsetName)
  4. public InputStreamReader(InputStream in, Charset cs)
  5. public InputStreamReader(InputStream in, CharsetDecoder dec)
  6. public int read() throws IOException {
  7. return sd.read();
  8. }
  9. public int read(char cbuf[], int offset, int length) throws IOException {
  10. return sd.read(cbuf, offset, length);
  11. }

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

  1. public class Test_InputOrOutput {
  2. public static void main(String[] args) throws IOException{
  3. InputStreamReader inr = new InputStreamReader(new FileInputStream("hello.txt"));
  4. char[] chs = new char[100];
  5. inr.read(chs);
  6. System.out.println(chs);
  7. inr.close();
  8. }
  9. }

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

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

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

  1. public class Test_InputOrOutput {
  2. public static void main(String[] args) throws IOException{
  3. OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("hello.txt"));
  4. ow.write("walker");
  5. ow.close();
  6. }
  7. }
  8. /*可以明显感知,对字符操作的简单直接*/

     三、文件字符流

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

  1. public FileReader(String fileName) throws FileNotFoundException {
  2. super(new FileInputStream(fileName));
  3. }
  4. public FileReader(File file) throws FileNotFoundException {
  5. super(new FileInputStream(file));
  6. }
  7. public FileWriter(String fileName) throws IOException {
  8. super(new FileOutputStream(fileName));
  9. }
  10. public FileWriter(String fileName, boolean append) throws IOException {
  11. super(new FileOutputStream(fileName, append));
  12. }
  13. public FileWriter(File file) throws IOException {
  14. super(new FileOutputStream(file));
  15. }

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

  1. public class Test_InputOrOutput {
  2. public static void main(String[] args) throws IOException{
  3. FileReader fr = new FileReader("hello.txt");
  4. char[] chars = new char[1024];
  5. fr.read(chars);
  6. System.out.println(chars);
  7. }
  8. }

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

  1. public class Test_InputOrOutput {
  2. public static void main(String[] args) throws IOException{
  3. InputStreamReader ins = new InputStreamReader(new FileInputStream("hello.txt"));
  4. char[] chars = new char[1024];
  5. ins.read(chars);
  6. System.out.println(chars);
  7. }
  8. }
  9. //因为FIleReader的内部还是通过super调用父类的构造方法

     四、字符数组流

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

  1. public class Test_InputOrOutput {
  2. public static void main(String[] args) throws IOException{
  3. FileReader fr = new FileReader("hello.txt");
  4. char[] chars = new char[1024];
  5. fr.read(chars);
  6. System.out.println(chars);
  7. }
  8. }

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

  1. public class Test_InputOrOutput {
  2. public static void main(String[] args) throws IOException{
  3. FileReader fr = new FileReader("hello.txt");
  4. int x = 0;
  5. CharArrayWriter chw = new CharArrayWriter();
  6. while ((x = fr.read()) != -1){
  7. chw.write(x);
  8. }
  9. System.out.println(chw.toString());
  10. chw.close();
  11. }
  12. }

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



     五、缓冲字符流

          字符的缓冲流和字节的缓冲流是类似的。都是装饰流。

  1. public class Test_InputOrOutput {
  2. public static void main(String[] args) throws IOException{
  3. BufferedReader bins = new BufferedReader(new FileReader("hello.txt"));
  4. BufferedWriter bws = new BufferedWriter(new FileWriter("hello.txt",true));
  5. int x;
  6. while ((x = bins.read()) != -1){
  7. System.out.println((char)x);
  8. bws.write(x);
  9. }
  10. }
  11. }
  12. //缓冲读和缓冲写

     六、PrintWriter

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

  1. protected Writer out;
  2. private final boolean autoFlush;
  3. //构造方法
  4. public PrintWriter (Writer out) {
  5. this(out, false);
  6. }
  7. public PrintWriter(OutputStream out) {
  8. this(out, false);
  9. }
  10. public PrintWriter(String fileName) throws FileNotFoundException {
  11. this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
  12. false);
  13. public PrintWriter(File file) throws FileNotFoundException {
  14. this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
  15. false);
  16. }
  17. //写入一个character
  18. public void write(int c) {
  19. try {
  20. synchronized (lock) {
  21. ensureOpen();
  22. out.write(c);
  23. }
  24. }
  25. catch (InterruptedIOException x) {
  26. Thread.currentThread().interrupt();
  27. }
  28. catch (IOException x) {
  29. trouble = true;
  30. }
  31. }
  32. //写入一个字符串
  33. public void write(String s) {
  34. write(s, 0, s.length());
  35. }
  36. //重载print方法
  37. public void print(boolean b) {
  38. write(b ? "true" : "false");
  39. }
  40. public void print(char c) {
  41. write(c);
  42. }
  43. public void print(int i) {
  44. write(String.valueOf(i));
  45. }
  46. public void println() {
  47. newLine();
  48. }
  49. public void println(int x) {
  50. synchronized (lock) {
  51. print(x);
  52. println();
  53. }
  54. }
  55. public void println(String x) {
  56. synchronized (lock) {
  57. print(x);
  58. println();
  59. }
  60. }

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

  1. public class Test_InputOrOutput {
  2. public static void main(String[] args) throws IOException{
  3. PrintWriter pw = new PrintWriter("hello.txt");
  4. pw.println('x');
  5. pw.close();
  6. }
  7. }

          使用了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. jqGrid Demos

    http://www.trirand.com/blog/jqgrid/jqgrid.html http://www.cnblogs.com/huozhicheng/archive/2012/11/11 ...

  2. Redis key 相关命令

    其实本质上,Redis 就是一个Key---Value 数据库.这里我先介绍下Redis中关于的key的相关命令, 注意:key是字符串存储,但是不能使用 空格 或者 “\n”,value 则可以使用 ...

  3. 在Oracle中数据库、表空间、表之间的关系

    在oracle中,表空间是存储概念上的,建立表空间需要有对应的数据文件,数据文件建立好之后直接会把一定的磁盘空间分配给它,这样可以对数据库的存储空间进行有效的管理.然后在建表的时候指定对应的表空间,该 ...

  4. 关于WIN10开机无法输入密码的问题

    昨日,电脑 遇到了开机无法输入密码的问题,神烦. 作为一个计算狗,怎么能直接装系统(百度了一堆方法,装系统,果真万能)呢. 所以,深刻的分析了下. 1 .首先说明基本情况. 计算机品牌:ASUS 系统 ...

  5. (译)AngularJS1.3.0 开发者指南(四) -- 控制器

    理解Controllers 在AngularJS中, Controller是一个Javascript构造函数, 常常被用来扩展 Angular Scope 对象. 控制器通过 ng-controlle ...

  6. CSS3知识点整理(一)----基本样式

    (一) 在编写CSS3样式时,不同的浏览器可能需要不同的前缀.它表示该CSS属性或规则尚未成为W3C标准的一部分,是浏览器的私有属性,虽然目前较新版本的浏览器都是不需要前缀的,但为了更好的向前兼容前缀 ...

  7. 如何快速赚钱:Python爬虫

    Python爬虫和毛爷爷的关系:Python是最简单最流行的开发语言,毛爷爷是最招人喜欢的人民币.如果你学会了Python爬虫,就可以挣更多的毛爷爷. 大家发现没有,实际上Python早已经火起来了, ...

  8. matlab中同一文件定义子函数的方法

    在matlab中一个.m文件中可以有多个的子函数,但仅能有一个主函数,并且M文件名必须和主函数相同在一个m文件中通常有两种定义子函数的方法: 1.嵌套定义 myfunc1会和主函数共享变量名.这种情况 ...

  9. LVS的十种调度算法

    LVS十种调度算法 1.静态调度: ①rr(Round Robin):轮询调度,轮叫调度 轮询调度算法的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重 ...

  10. 用phpcms如何将静态页面制作成企业网站,头部加尾部

    首先,先要准备好这个静态网页的源文件,如图 bs里面是一些css和js的文件,img则是放图片的,文件中的index是网页的首页 运行一下,看看 是这样的 然后打开phpcms文件,上篇博客中有提到, ...