Java打印流

/ Java / 0 条评论 / 4204浏览

问题引入

在之前学习OutputStream的时候,如果要输出一个数据都是通过调用其write方法,但是所有的write方法传入的数据类型都是byte类型的,如果我们要输出int、double、boolean等类型的数据的时候都需要将其转换成String类然后再转换成byte数组进行输出,那么这样的话就会写很多重复的代码。

打印流:PrintStream和PrintWriter

在java中为了解决上面的问题,专门新增了两个类:PrintStream(打印字节流)、PrintWriter(打印字符流)。

这两个类的方法几乎相同,只是他们对操作对象有所不同,一个是字节数据一个是字符数据,这里以PrintStream为例。

方法定义:

public class PrintStream extends FilterOutputStream implements Appendable, Closeable

继承结构:

java.lang.Object
    java.io.OutputStream
        java.io.FilterOutputStream
            java.io.PrintStream

构造方法(仅列出两个主要的构造方法):

public PrintStream(OutputStream out)
public PrintStream(File file)

发现它是OutputStream的子类,FilterOutputStream是一个过滤输出类,可以先不用看它。需要关注的是它的构造方法,发现它可以接受OutputStream的对象,同时又继承OutputStream类,看似有点像代理设计模式,其实不是,我们看看它的方法

FilterOutputStream:

This class is the superclass of all classes that filter output streams. These streams sit on top of an already existing output stream (the underlying output stream) which it uses as its basic sink of data, but possibly transforming the data along the way or providing additional functionality.

方法函数(不包含重载):

public void print(boolean b)
public void print(char c)
public void print(int i)
public void print(long l)
public void print(float f)
public void print(double d)
public void print(char[] s)
public void print(String s)
public void print(Object obj)

//  换行输出
public void println()   
public void println(boolean x)
public void println(char x)
public void println(int x)
public void println(long x)
public void println(float x)
public void println(double x)
public void println(char[] x)
public void println(String x)
public void println(Object x)

//  格式化输出
public PrintStream printf(String format, Object... args)
public PrintStream printf(Locale l, String format, Object... args)

从它的方法里面可以看到支持各种数据的输出,通过观察其源码发现,它都是对OutputStream对象的write方法进行一些修改,仅仅是帮我们把各种数据转换为byte字节数据而已,也就是说归根结底还是使用的OutputStream的write方法,这种实现模式是修饰设计模式。

修饰模式 (Decorator pattern) ,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。

下面通过一段代码来使用上面的方法,简单应用一下:

打印输出至文件:

package language;

import java.io.File;
import java.io.PrintStream;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:20 2019/1/26
 * @Description:
 */
public class PrintStreamTest {

    public static void main(String[] args) throws Exception{
        File file = new File("D:"+File.separator+"test.txt");       //  将打印删除的文件
        PrintStream printStream = new PrintStream(file);
        printStream.print("你好啊");
        printStream.print(123);
        printStream.print(123.459897651);
        printStream.print(true);
        printStream.close();
    }
}

打印输出到内存:

package language;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintStream;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:20 2019/1/26
 * @Description:
 */
public class PrintStreamTest {

    public static void main(String[] args) throws Exception{
        OutputStream outputStream = new ByteArrayOutputStream();        //  内存流(针对程序是输出,针对内存是输入)
        PrintStream printStream = new PrintStream(outputStream);        //  创建打印流,并将内存流传入
        printStream.println("你好啊");
        printStream.print(123);
        printStream.print(123.459897651);
        printStream.print(true);
        printStream.close();

        System.out.println(outputStream);   //  调用toString方法将内存中的数据以字符串输出
        System.out.println("占用内存空间:"+((ByteArrayOutputStream) outputStream).size());
        outputStream.close();
    }
}

格式化输出

在jdk1.5之后新增了一种输出方式:格式化输出,我们看到在PrintStream类中多了两个方法:format和printf。这两个方法的作用归根结底都是进行格式化输出,什么是格式化输出?其实在c语言中printf方法和这个是一样的,就是在字符串中以特定的符号来代表某种数据类型进行字符拼接。

整形(%d)、浮点型(%f)、确定小数位的浮点型(%m.nf)、字符串(%s)、字符(%c)

下面将上一部分的代码进行修改:

package language;

import java.io.*;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:20 2019/1/26
 * @Description:
 */
public class PrintStreamTest {

    public static void main(String[] args) throws Exception{
        File file = new File("D:"+File.separator+"test.txt");       //  将打印删除的文件
        PrintStream printStream = new PrintStream(file);

        String name = "beifengtz";
        int age = 20;
        double height = 1.75;
        double weight = 57.77777777777;

        printStream.printf("你好啊!我叫%s,今年%d,我的身高是%f,体重%5.2f",name,age,height,weight);
        printStream.close();
    }
}

在test.txt文件中的结果:

你好啊!我叫beifengtz,今年20,我的身高是1.750000,体重57.78

这个格式化方法其实在String中也有,也是在jdk1.5开始出现的,下面简单应用一下String类中的format方法:

package language;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:20 2019/1/26
 * @Description:
 */
public class PrintStreamTest {

    public static void main(String[] args) throws Exception{

        String name = "beifengtz";
        int age = 20;
        double height = 1.75;
        double weight = 57.77777777777;
        String str = String.format("你好啊!我叫%s,今年%d,我的身高是%f,体重%5.2f", name,age,height,weight);

        System.out.println(str);
    }
}

输出结果和上面一样,下面是String类中format的定义(Locale仅用于字符编码,本地化应用):

public static String format(Locale l, String format, Object... args)

public static String format(String format, Object... args)

System类中的io

System.out.println是我们经常使用的操作,但是大部分初学者都仅限于会用他的,对于他的内部构造并没有深究(其实我之前也是),那么下面来学习一下System类对io的支持。

首先要明白System类中定义的三个常量:

看到这是哪个常量之后,不明觉厉,err和out是PrintStream类型,in是InputStream类型,都是字节流的输入和输出。这也就是说System类是通过io操作来进行输入输出的,在Java中没有提供直接的标准输入输出,都是io操作。

输出

其中err和out几乎完全相同,唯一不同的一点是err在输出的时候字体标红以表示错误或警告。

System类是不需要我们手动实例化的,它是系统自动实例化的,使用native关键字来调用c函数库,下面是源码中三个常量的注册代码:

    private static native void setIn0(InputStream in);
    private static native void setOut0(PrintStream out);
    private static native void setErr0(PrintStream err);

因为上面学了PrintStream类的方法,所以这里就不再过多演示,只要了解到,输出方法来源于PrintStream即可

package language;

import java.io.PrintStream;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:20 2019/1/26
 * @Description:
 */
public class PrintStreamTest {

    public static void main(String[] args) throws Exception{
        PrintStream out = System.out;
        System.out.println("hello");
        out.println("hello");
    }
}

控制台输出结果:

hello
hello

输出

其实System类中提供的输出也是和之前学习的非常类似的,只要我们知道System.in类是InputStream类型的,我们在输入的时候就可以直接使用它的函数,只是数据的来源不是之前例子中的文件和内存,而是键盘而已,其他操作方法一样,但是其实现方法却有所不同,如果是我们自己去实现其中的方法,当有中文时可能会出现乱码情况,具体内容下一篇博客见。。。

package language;

import java.io.InputStream;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:20 2019/1/26
 * @Description:
 */
public class PrintStreamTest {

    public static void main(String[] args) throws Exception{

        //此段程序有中文乱码以及数组越界问题,具体处理办法见下一篇博客!!!

        InputStream inputStream = System.in;
        byte[] data = new byte[1024];
        System.out.println("请输入数据");
        int len = inputStream.read(data);
        System.out.println("输入的数据为:"+new String(data,0,len));
        inputStream.close();
    }
}

控制台输出结果:

请输入数据
1253
输入的数据为:1253

微信公众号浏览体验更佳,在这里还有更多优秀文章为你奉上,快来关注吧!

北风IT之路