浅谈PrintStream和PrintWriter的区别和联系

前言

这两者在往文件中写入字符串时,最终都需要通过字符集的映射关系得到对应字节。

但这二者在通过char得到对应若干字节的时机不一样,以new PrintStream( new BufferedOutputStream( new FileOutputStream("BasicFileOutput.out")));new PrintWriter( new BufferedWriter( new FileWriter("BasicFileOutput.out")))为例,前者在存字符串时,从PrintStream传到BufferedOutputStream时就已经是字节了;后者在存字符串时,直到FileWriter真正写入文件时,才将字符转换为字节。

如果PrintStream被设置为autoFlush,那么这些情况flush方法将会自动执行:写入字节数组、任何重载版本的println被调用、一个换行符(char)被写入、一个换行符的字节存储(\n)被写入。

如果PrintWriter被设置为autoFlush,那么这些情况flush方法将会自动执行:println、printf、format方法被调用。

它们都不会抛出IO异常,因为它们在方法内部捕获住了,可以通过checkError()来判断是否发生异常。

PrintWriter会使用平台特有的换行符(比如Windows和linux),PrintStream则固定使用\n

总的来说,Reader/Writer相比InputStream/OutputStream算是一种升级,将当初设计得不好的地方进行了优化。

二者的构造器分析

这二者真的很像,你可以去看它们俩的api文档,可以发现它们的构造器和方法几乎一模一样。

你会注意到PrintWriter的构造器中,也可以指定字符集,这可能有点奇怪,因为作为用来装饰的Writer(PrintWriter)来说,它应该不需要关心字符应该怎么对应到字节上去,只需要关心字符就好了呀。

PrintWriter有两个构造器都可以指定字符集:PrintWriter(File file, String csn)PrintWriter(String fileName, String csn),但这两个构造器最终都会调用到下面这个构造器,可以看出charset是给装饰器最里层的FileOutputStream使用的,而外层的两个Writer都不用关心。这说明Writer确实不需要关心字符集。

 /* Private constructor */
  private PrintWriter(Charset charset, File file)
    throws FileNotFoundException
  {
    this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)),
       false);
  }

其实PrintStream也很low,观察它的构造器可以发现它竟然是靠BufferedWriter来驱动的(这看起来和上面贴的PrintWriter的构造器里的逻辑一样,这里指装饰器的装饰过程):

/* Private constructors */
  private PrintStream(boolean autoFlush, OutputStream out) {
    super(out);
    this.autoFlush = autoFlush;
    this.charOut = new OutputStreamWriter(this);//往自己身上装饰一层
    this.textOut = new BufferedWriter(charOut);//往自己身上再装饰一层
  }

  private void write(String s) {
    try {
      synchronized (this) {
        ensureOpen();
        textOut.write(s);//先调用最外层的流的write函数
        textOut.flushBuffer();
        charOut.flushBuffer();
        if (autoFlush && (s.indexOf('\n') >= 0))
          out.flush();
      }
    }
  ...
  }

也就是说,这句new PrintStream( new BufferedOutputStream( new FileOutputStream("BasicFileOutput.out")));实际上会产生五个流对象(装饰器模式会套五层,禁止套娃!)。看write函数,每次写入字符串时,竟然是先通过装饰器最外层的BufferedWriter进行的写入,然后再执行BufferedWriter、OutputStreamWriter的flushBuffer函数把字符转换为字节(像挤牙膏一样,只不过这是从外往里挤),并且将字节弄到this对象里面。

PrintStream的三种类型(File、OutputStream、String)的构造器都可以带字符集。

我们随便看一个带字符集的构造器,发现字符集被设置在this的外面一层流上,所以通过OutputStreamWriter向this传递字节数组时,这个字节数组就已经经过了特定字符集charset的encode了:

 private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
    super(out);
    this.autoFlush = autoFlush;
    this.charOut = new OutputStreamWriter(this, charset);
    this.textOut = new BufferedWriter(charOut);
  }

PrintWriter相比PrintStream多了一种类型的构造器(File、OutputStream、String、Writer),那就是它还可以接受一个Writer。

二者的方法分析

对比二者的api文档,你会发现前面的方法签名,这二者都是一模一样,除了后面的write方法们,所以我们只看不同的部分。相同的部分占大部分,同学们可以自行查看。

PrintStream的write方法们

从方法的描述也可以看出,这些write方法都是针对byte或者byte[ ]的。

发现有一个write方法是从FilterOutputStream继承而来,因为这个重载版本的write方法PrintStream没有去重写父类方法(下面这两个就是重写了FilterOutputStream了的)。

FilterOutputStream的write(byte[] b)版本如下:

PrintWriter的write方法们

从方法的描述也可以看出,这些write方法都是针对char或者string的。

到此这篇关于浅谈PrintStream和PrintWriter的区别和联系的文章就介绍到这了,更多相关PrintStream和PrintWriter区别内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • PrintStream和PrintWriter的区别简介

    PrintStream和PrintWriter的API几乎相同,都能输出各种形式的数据,构造方法也几乎相同 PrintWriter多了个接受Writer参数 API比较: 那么,它们的区别究竟在哪里?来自stackflow 主要意思就是,2个类的功能基本相同,PrintStream能做的PrintWriter也都能实现,并且PrintWriter的功能更为强大.但是由于PrintWriter出现的比较晚,较早的System.out使用的是PrintStream来实现的,所以为了兼容就没有废弃Pr

  • 浅谈PrintStream和PrintWriter的区别和联系

    前言 这两者在往文件中写入字符串时,最终都需要通过字符集的映射关系得到对应字节. 但这二者在通过char得到对应若干字节的时机不一样,以new PrintStream( new BufferedOutputStream( new FileOutputStream("BasicFileOutput.out")));和new PrintWriter( new BufferedWriter( new FileWriter("BasicFileOutput.out")))为

  • 浅谈cookie 和session 的区别

    具体来说 cookie 是保存在"客户端"的,而session是保存在"服务端"的 cookie 是通过扩展http协议实现的 cookie 主要包括 :名字,值,过期时间,路径和域: 如果cookie不设置生命周期,则以浏览器关闭而关闭,这种cookie一般存储在内存而不是硬盘上.若设置了生命周期则相反,不随浏览器的关闭而消失,这些cookie仍然有效直到超过设定的过 期 时间. session 一种类似散列表的形式保存信息, 当程序需要为某个客户端的请求创建一个

  • 浅谈Ajax和JavaScript的区别

    javascript是一种在浏览器端执行的脚本语言,Ajax是一种创建交互式网页应用的开发技术 ,它是利用了一系列相关的技术其中就包括javascript. Javascript是由网景公司开发的一种脚本语言,它和sun公司的java语言是没有任何关系的,它们相似的名称只是一种行销策略. 在一般的web开发中,javascript是在浏览器端执行的,我们可以用javascript控制浏览器的行为和内容. 在 Ajax应用中信息是如何在浏览器和服务器之间传递的. 通过XML数据或者字符串 以上这篇

  • 浅谈sql连接查询的区别 inner,left,right,full

    --table1 表 ID NAME QQ PHONE 1 秦云 10102800 13500000 2 在路上 10378 13600000 3 LEO 10000 13900000 4 秦云 0241458 54564512 --table2 表 ID NAME sjsj gly 1 秦云 2004-01-01 00:00:00.000 李大伟 2 秦云 2005-01-01 00:00:00.000 马化腾 3 在路上 2005-01-01 00:00:00.000 马化腾 4 秦云 20

  • 浅谈addEventListener和attachEvent的区别

    • addEventListener共有3个参数,如下所示: element.addEventListener(type,listener,useCapture); 参数 参数说明 element 要绑定事件的对象,及HTML节点. type 事件名称,注意去掉事件前边的"on",比如"onclick"要写成"click","onmouseover"要写成"mouseover". listener 要绑定的

  • java集合_浅谈Iterable和Iterator的区别

    1). Iterator是迭代器类,而Iterable是为了只要实现该接口就可以使用foreach,进行迭代. 2). Iterable中封装了Iterator接口,只要实现了Iterable接口的类,就可以使用Iterator迭代器了. 3). 集合Collection.List.Set都是Iterable的实现类,所以他们及其他们的子类都可以使用foreach进行迭代. 4). Iterator中和核心的方法next(),hasnext(),remove(),都是依赖当前位置,如果这些集合直

  • 浅谈toLowerCase和toLocaleLowerCase的区别

    ECMAScript中涉及字符串大小写转换的方法有4个:toLowerCase().toLocaleLowerCase().toUpperCase()和toLocaleUpperCase(). 其中,toLowerCase()和toUpperCase()是两个经典的方法,借鉴自java.lang.String中的同名方法.而toLocaleLowerCase()和toLocaleUpperCase()方法则是针对特定地区的实现. 对有些地区来说,针对地区的方法与其通用方法得到的结果相同,但少数语

  • 浅谈c++ 字符类型总结区别wchar_t,char,WCHAR

    1.区别wchar_t,char,WCHAR ANSI:即 char,可用字符串处理函数:strcat( ),strcpy( ), strlen( )等以str打头的函数. UNICODE:wchar_t是Unicode字符的数据类型,它实际定义在里: typedef unsigned short wchar_t; 另外,在头文件中有这样的定义:typedef wchar_t WCHAR; 所以WCHAR实际就是wchar_t wchar_t 可用字符串处理函数:wcscat(),wcscpy(

  • 浅谈pytorch和Numpy的区别以及相互转换方法

    如下所示: # -*- coding: utf-8 -*- # @Time : 2018/1/17 16:37 # @Author : Zhiwei Zhong # @Site : # @File : Numpy_Pytorch.py # @Software: PyCharm import torch import numpy as np np_data = np.arange(6).reshape((2, 3)) # numpy 转为 pytorch格式 torch_data = torch.

随机推荐