Java print流简介

接下来这篇博文介绍java另1种Stream, print 流.  亦有人称其为打印流.


介绍这个print流之前有必要明确两点:

1. print 流是输出流, 只能用于输出到外部设备不能用于输入.

2. print 流是包裹流(处理流), 必须包裹在另1个流之上.


一, 其他输出流介绍

要了解print流的由来, 有必要明白print流和其他输出流的区别.

在这里首先重新go through一次一起博文介绍过的若干常用的输出流.


1.1 Writer

Writer是1个流的上层抽象类,  我们常用的FileWriter, CharArrayWriter 都是继承自这个类.

利用writer的 各种重载的write()方法可以写入

1. 1个字符 write(int) //字符二进制数据存放在int类型中

2. 1个字符数组 write(char[])

3. 1个字符数组的一部分 write(char[],int,int)

4. 1个字符串 或者 一个字符串的一部分 write(String,0,len)


Wirter的优点就是方便地处理字符外部设备(例如文本文件) 但是不能处理二进制外部设备(类如mp3文件).


1.2 OutputStream

OutputStream也是1个上层抽象类, 相对于Writer,OutputStream一次只能写入1个字节, 而不是字符.

我们常用的 FileOutputStream, ByteArrayOutputStream 都是继承自这个流.


利用OutputStream 可以的write方法可以写入

1. 1个字节 write(int)

2. 1个字节数组 write(byte[])

3. 1个字节数组的一部分 write(byte[],int,int)


OutputStream的优点就是可以处理一切文件, 包括文本文件和二进制文件.



1.3 DataOutputStream

基本上所有作为原始流的输出流都是继承子上面的两个抽象类(Writer 和 OutputStream)

而这个DataOutputStream 则是1个继承自OutputStream的1个包裹流, 它必须包裹在1个OutputStream的原始流之上.


利用DataOutputSream, 可以写入

1. 1个字节 write(int)

2. 1个字节数组 write(byte[])

3. 1个字节数组的一部分 write(byte[],int,int)


前面这3个都是继承自OutputStream, 没什么特别. 关键是下面这个

所有基本类型的二进制代码.

例如:

4. 1个int类型的二进制数据 writeInt(int)

5. 1个foat类型的二进制数据 writeFloat(float)

....


简单地讲,

如果执行 DataOutputStream 的 writeInt(100) 就会把100的二进制代码 1100100, 也就是 00 00 00 64(16进制表示) 写入到外部设备. 共占4个字节


1.3.1 DataOuputStream 1个例子

这个例子步骤很简单.

就是利用DataOutputStream 往1个文件(/home/gateman/tmp/testStream1.txt) 写入1个int类型 值是: 1229935882.

然后查看这个文件的内容.


代码如下:

import java.io.*;

public class DataStream2{
    public static void f(){
        try{
            g();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    
    public static void g() throws IOException{
        int i = 1229935882;

        File f = new File("/home/gateman/tmp/testStream1.txt");
        if (f.exists()){
            f.delete();
        }

        f.createNewFile();

        FileOutputStream fos = new FileOutputStream(f);
        DataOutputStream dos = new DataOutputStream(fos);
        
        dos.writeInt(i);
        dos.flush();
        dos.close();
        
        System.out.printf("done!!\n"); 
    }
}


代码很容易读懂, 这里不解释了.

当执行完这代码后, 首先用cat命令来查看这个文件的内容

gateman@TPEOS Java_1 $ ant
Buildfile: /media/store1/Studies/Java/java_start/Java_1/build.xml

main:
    [javac] /media/store1/Studies/Java/java_start/Java_1/build.xml:10: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
     [java] done!!

BUILD SUCCESSFUL
Total time: 0 seconds
gateman@TPEOS Java_1 $ cat /home/gateman/tmp/testStream1.txt 
IOU

简单文件的内容不是 数字1229935882,  而是三个字母 "IOU".

为何呢?


原因就是DataOutputStream会将 int类型1229935882 转换成 2进制

用16进制来表示就是 49 4f 55 0a. 

至于10进制如何转换成16进制这里就不深究了.


我们可以用xxd来查看1个文件的2进制(16进制)内容:

gateman@TPEOS Java_1 $ xxd -g 1 /home/gateman/tmp/testStream1.txt
0000000: 49 4f 55 0a                                      IOU.

可以见到.

0000000: 这些是文件头部信息.

内容就是

49 4f 55 0a

那么为何输出是IOU?


因为cat命令不是输出文件的2进制代码命令, 而是将其视为1个文本文件来输出.

那么就会利用ASCII码来对文件的2进制数据进行编码.


在ASCII表中

16进制 49 -> 10进制 73 -> 字符'I'

4f -> 79 -> O

55 -> 85 -> U

0a -> 10 -> 换行符


所以用cat转码后输出就是"IOU\n"了

当然, 如果利用一般的文本编辑器打开, 例如vi, gedit等打开这个文件, 显示的文件内容也是IOU哦.




二, Print流介绍

上面提过了, print流是输出流的一种, 它也继承自基本的抽象类OutputStream 或 Writer.

除了继承过来(实际上是重写)的基本的write()方法之外,  print 流更重要的是具有多种的重载的print(), printf() 和 println()方法.


这些print()方法能用于各种不同类型数据的格式话输出.


例如DataOutputStream的 writeInt(int)能往外部设备写入 int类型数值的二进制数据.

而print流的 print(int)则可以往外部设备写入 Int类型数值的格式化输出.


再简单地讲:

DataOutputStream的 writeFloat(8.8) 写入的是8.8这个数值的二进制编码.

而PrintStream(printWriter)的 print(8.8) 写入的是'8', '.', '8' 这个3个字符.


2.1 一个例子

这个例子用于和上面例子做个对比.

我们利用PrintStream, 同样往1个文件写入 1229935882 这个int类型数据, 然后查看文件的内容.


代码如下:

import java.io.*;

public class PrintStream1{
    public static void f(){
        try{
            g();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    
    public static void g() throws IOException{
        int i = 1229935882;

        File f = new File("/home/gateman/tmp/testStream2.txt");
        if (f.exists()){
            f.delete();
        }

        f.createNewFile();

        FileOutputStream fos = new FileOutputStream(f);
        PrintStream ps = new PrintStream(fos);
        
        ps.print(i);
        ps.print('\n');
        ps.flush();
        ps.close();
        
        System.out.printf("done!!\n"); 
    }
}


可见上面DataOutputStream的改动很小, 只是把DataOutputStream 改成 PrintStream

输出:

gateman@TPEOS Java_1 $ cat /home/gateman/tmp/testStream2.txt 
1229935882
gateman@TPEOS Java_1 $ 

可见 被写入的外部文件中就只是 '1229935882\n' 这个几个字符了.



三, Print流分类

我们常说的print流有两个


其中1个就是上面例子中的PrintStream. 它继承自OutputStream

另1个就是PrintWriter就是 Writer.


3.1 PrintStream

PrintStream继承自OuputStream的子类FilterOutputStream

PrintStream的方法都不会抛出IOException异常, 而是使用另一种error handling机制.

PrintStream必须包裹在另1个OutputStream上使用.


PrintStream的println()方法会产生'\n'换行符.


3.2 PrintWriter

printWriter继承自Writer

具有与PrintStream一样的方法.

它的方法也不会抛出IOException.

PrintWriter既可以包裹在Writer原始流使用, 也可以包裹在另1个OutputStream上.


PrintWriter的println()方法会根据不同的操作系统产生对应的换行符, 例如在linux下换行符是'\n', 在windows下的换行符则是'\r\n'



3.3 PrintStream 和 PrintWriter的区别

它们两者的使用方法基本上可以一样的.

区别有两个

1. PrintWriter可以包裹在另1个Writer上使用, 也可以包裹在另1个OutputStream上使用, 而PrintStream只能包裹在另1个OutputStream上使用.

2. PrintWriter的println()方法跨平台性更加好.



四, 常用的Print流

看到了pint() println()这些方法是不是想起我们常用的输出字符到屏幕的命令 System.out.println().

的确, System.out就是java系统封装好的1个指向标准输出设备的静态print流.


实际上System这个类有3个静态流

其中两个是PrintStream, 分别是

System.out  标准输出流(PrintStream), 默认指向屏幕

System.err   标准错误输出流(PrintStream),默认指向屏幕

System.in    标准输出流(InputStream), 默认指向键盘



4.1 System.out

首先, 要明白, System是1个类, 而不是1个包.

System: System是Java内部的类, 它包含了许多常用的静态字段和静态方法, 它不能实例化.


out: 而out是System的1个静态属性, 它指向java系统封装好的指向标准输出设备的一个静态PrintStream(注意不是PrintWriter)

标准输出设备: 所谓的标准设备就是计算的屏幕. 但是这个标准输出设备可以被改变.


setOut(PrintStream out): 利用setOut()方法可以改变标准输出设备, 例如我们可以将标准输出设备设置为1个FileOutputStream, 那么以后我们执行System.out.println()方法时, 就不再把信息输出到屏幕, 而是输出到那个FileOutputStream, 也就是1个文件里了.


简单地讲, A是1个PrintStream, 执行System.set(A)后,  System.out就等于A!



例子:

import java.io.*;

public class SystemOut1{

    public static void f(){
        try{
            g();
        }catch(IOException e){
            e.printStackTrace();
        }
    }

    public static void g() throws IOException{
        PrintStream screenOS = System.out;//marked down
        System.out.println("It will be printed to monitor!");
        
        File f = new File("/home/gateman/tmp/testStream3.txt");

        if (f.exists()){
            f.delete();
        }

        FileOutputStream fos = new FileOutputStream(f);
        PrintStream ps = new PrintStream(fos,true); // autoflush = true;
        // PrintStream ps = new PrintStream(f); //another constructor;
        
        System.setOut(ps);
        System.out.println("It will be printed to file!");

        System.setOut(screenOS);// set to default value
        System.out.println("It will be printed to monitor again!");
        
        ps.close();
    }
}

上面代码执行了三次System.out.println()方法.

第1次: 因为System.out是指向标准输出设备(屏幕)的PrintStream. 所以第一句被输出到了屏幕.

第2次: 标准输出设备被System.setOut()方法改变成了1个指向文件的PrintStream. 所以第二句被输出到了文件.

第3次: 标准输出设备再次被修改为默认值, 所以第三句输出到了屏幕.


执行结果:

gateman@TPEOS Java_1 $ ant
Buildfile: /media/store1/Studies/Java/java_start/Java_1/build.xml

main:
    [javac] /media/store1/Studies/Java/java_start/Java_1/build.xml:10: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 1 source file to /media/store1/Studies/Java/java_start/Java_1/build/classes
     [java] It will be printed to monitor!
     [java] It will be printed to monitor again!

BUILD SUCCESSFUL
Total time: 1 second
gateman@TPEOS Java_1 $ cat /home/gateman/tmp/testStream3.txt 
It will be printed to file!


4.2 System.err

System.err 也是1个静态PrintStream.

作为程序猿, 很多情况下需要处理程序的错误, 当错误发生时, 我们会把一些错误信息输出.

System.err 实际上就是1个指向标准错误输出设备的PrintStream.

所谓标准错误输出设备是什么? 默认也是屏幕, 但是很多情况下我们会修改其为1个专门存储错误信息的log文件.


有两个常用的方法会利用System.err


1个就是直接执行System.err的printf/print/println()方法.

另1个就是Exception的方法printStackTrace(); 这个方法实际上也是输出到标准错误输出设备.


同理, 我们也可以利用System.setErr()方法来改变标准错误输出设备的指向.


例子:

import java.io.*;

public class SystemErr1{

    public static void f(){
        try{
            g();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    public static void h() throws IOException{
        throw new IOException("Shit !!! / by zero!");
    }

    public static void g() throws Exception{
        int i = 0;
        int j =0;
        File f = new File("/home/gateman/tmp/testStream4.txt");

        if (f.exists()){
            f.delete();
        }

        FileOutputStream fos = new FileOutputStream(f);
        PrintStream ps = new PrintStream(fos,true); // autoflush = true;
        // PrintStream ps = new PrintStream(f); //another constructor;
        
        try{
          j = 3 / i;  
        }catch(Exception e){
            System.err.println("this err msg will be printed to monitor!");
            e.printStackTrace();
        }
        
        System.setErr(ps);

        try{
           h(); 
        }catch(Exception e){
            System.err.println("this err msg will be printed to file!");
            e.printStackTrace();
        }
        
        ps.close();
    }
}

上面的代码输出次错误信息.

第一次输出到屏幕

第二次输出到1个文件


执行结果:

gateman@TPEOS Java_1 $ ant
Buildfile: /media/store1/Studies/Java/java_start/Java_1/build.xml

main:
    [javac] /media/store1/Studies/Java/java_start/Java_1/build.xml:10: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
     [java] this err msg will be printed to monitor!
     [java] java.lang.ArithmeticException: / by zero
     [java] 	at Stream_kng.PrintStream_kng.SystemErr1.g(SystemErr1.java:33)
     [java] 	at Stream_kng.PrintStream_kng.SystemErr1.f(SystemErr1.java:9)
     [java] 	at Enter_1.main(Enter_1.java:95)
     [java] 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java] 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     [java] 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     [java] 	at java.lang.reflect.Method.invoke(Method.java:601)
     [java] 	at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:217)
     [java] 	at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:152)
     [java] 	at org.apache.tools.ant.taskdefs.Java.run(Java.java:771)
     [java] 	at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:221)
     [java] 	at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:135)
     [java] 	at org.apache.tools.ant.taskdefs.Java.execute(Java.java:108)
     [java] 	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
     [java] 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     [java] 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     [java] 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     [java] 	at java.lang.reflect.Method.invoke(Method.java:601)
     [java] 	at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
     [java] 	at org.apache.tools.ant.Task.perform(Task.java:348)
     [java] 	at org.apache.tools.ant.Target.execute(Target.java:435)
     [java] 	at org.apache.tools.ant.Target.performTasks(Target.java:456)
     [java] 	at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1393)
     [java] 	at org.apache.tools.ant.Project.executeTarget(Project.java:1364)
     [java] 	at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
     [java] 	at org.apache.tools.ant.Project.executeTargets(Project.java:1248)
     [java] 	at org.apache.tools.ant.Main.runBuild(Main.java:851)
     [java] 	at org.apache.tools.ant.Main.startAnt(Main.java:235)
     [java] 	at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
     [java] 	at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)

BUILD SUCCESSFUL
Total time: 0 seconds
gateman@TPEOS Java_1 $ cat /home/gateman/tmp/testStream4.txt 
this err msg will be printed to file!
java.io.IOException: Shit !!! / by zero!
	at Stream_kng.PrintStream_kng.SystemErr1.h(SystemErr1.java:16)
	at Stream_kng.PrintStream_kng.SystemErr1.g(SystemErr1.java:42)
	at Stream_kng.PrintStream_kng.SystemErr1.f(SystemErr1.java:9)
	at Enter_1.main(Enter_1.java:95)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:217)
	at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:152)
	at org.apache.tools.ant.taskdefs.Java.run(Java.java:771)
	at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:221)
	at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:135)
	at org.apache.tools.ant.taskdefs.Java.execute(Java.java:108)
	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
	at org.apache.tools.ant.Task.perform(Task.java:348)
	at org.apache.tools.ant.Target.execute(Target.java:435)
	at org.apache.tools.ant.Target.performTasks(Target.java:456)
	at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1393)
	at org.apache.tools.ant.Project.executeTarget(Project.java:1364)
	at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
	at org.apache.tools.ant.Project.executeTargets(Project.java:1248)
	at org.apache.tools.ant.Main.runBuild(Main.java:851)
	at org.apache.tools.ant.Main.startAnt(Main.java:235)
	at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
	at org.apache.to


4.2 标准输出和标准错误输出的重定向

在项目编程中, 有时我们需要把正常输出到1个文件, 错误输出到另外一个文件方便记录和以后查看, 这时我们可以利用System.setOut() 和 System.setErr()方法来改变输出的指向.

这个就是所谓的标准和标准错误的重定向输出了.




















  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nvd11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值