Java 转换流 简介

来源:互联网 发布:ubuntu kernel devel 编辑:程序博客网 时间:2024/06/11 21:19

在以前的博文也提过了, java的Stream根据传输的最小单位, 可以分为字符流和字节流. 


字节流应用面更广,  而字符流在某些情况(例如文本处理)会更加方便.


而在编程中,  有时程序接收到的是一条字节流(前提是确定该流存储的是字符数据), 而程序员又想将其当字符流来处理. 就可以利用java中的InputStreamReader 和 OutputStreamWriter.


一, 什么是转换流及作用

上面提到的两个流:   InputStreamReader 和 OutputStreamWriter 在Java中就被称为转换流.


以前我们提到   InputStream 和 OutputStream代表的是字节流,  而 Reader 和 Writer代表字符流

那么它们写在一起是什么流?


实际它们是处理流的一种,  必须包裹在1个字节流之上, 然后能当左字符流来处理. 相当于把1个字节流转换为1个字节流. 而无需关心编码方式(Java用的是万国码).


另1个问题:

有没有反过来, 把字符流转为字节流的转换流呢?  答案是:  Java没有提供.  如有必要, 字节可以写1个哦.



二, 1个例子

至于上面转换流的常用方法就不一样介绍了, 无非常用的就是 read() 和 write(), 跟字符流的对应方法基本一样的.


现在写1个例子:

接受用户键盘输入的1行字符(直至回车).  放入1个字符串中.


首先分析一下题目.

这个需求简单地将就是接受 由外部设备(键盘) 发送的数据, 接收到程序的1个String变量上.


2.1. 首先就要构造1个从键盘到程序的字节流

我们需要的字符, 为什么要构造1个字节流呢?  因为能直接连接键盘的流只有字节流...


如果我们建立1个从文件(外部设备)到程序的InputStream,

则必须利用文本流

new FileInputStream(File f)


而在java中,键盘同样会被当做1个外部输入设备.

这个外部输入设备有点特殊, 因为键盘会当成默认的系统输入设备. 也叫标准输入流.


而连接系统输入设备字节流java已经帮我们封装好了, 它就是

System.in


其中System是1个类,

in 是System类的1个静态字段(非方法), 它返回的就是标准输入流的对象.


同样地, Java中也有1个标准输出流, 它就是 System.out(同样是1个静态字段, 返回1个流向标准输出设备的OutputStream) 这个流的输出目标默认就是计算机屏幕执行Java程序的终端.

当然, 这个默认值是改变的, 我们可以利用System.setOut()来修改, 再下一篇博文会详细提到.


具体可以看JDK API, java.lang.System类:


public static final InputStream in
“标准”输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。
out

public static final PrintStream out
“标准”输出流。此流已打开并准备接受输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。
对于简单独立的 Java 应用程序,编写一行输出数据的典型方式是:

     System.out.println(data)



2.2 将标准输入流System.in 转为字符输入流

如果你看懂我上面写的什么的话, 就可以知道System.in 就是我们想要的从键盘到程序的一条输入字节流.

但是对于1个字节流来讲,我们只能从它读取1个字节or1个字节数组.  但是我们需要的是字符数据.


所以有必要将其转换为字符流.

那么本文的主角, 转换流 InputStreamReader就发挥作用了.

 

new InputStreamReader(System.in)

上面代码就获得1条从键盘通向程序的字符流了.


2.3 从字符流里读取一行.

上面的字符流提供了基本的read()方法,

可以读取1个字符和1段字符数组.


问题是如何读取一行呢?

首先要搞清楚什么是一行字符:   就是第一个换行符"\n"(回车) 之前的所有字符


2.3.1 方法1

既然知道了所谓一行字符就是换行符"\n" 之前的所有字符.

那么我们可以循环地执行  read() 方法去每次读取1个字符, 然后把这个字符存放到1个StringBuffer中, 直至遇到"\n"

比如:



有人可能回问,  r.read()这个方法不是由键盘trigger的吗? 不是应该卸载1个事件中?

实际上, 键盘在这里只是1个外部设备.


而执行1次  r.read();  (r就是字符流对象)时,  程序会一直等键盘输入, 知道键盘按下1个字符.

也就是说, 如果键盘无输入时, 程序就一直在等待.

所以, 指向键盘字符流的read()时不需要写在1个event里面的.

        StringBuffer sbuffer = new StringBuffer(1024);        int ic = 0;        char c;        Reader r = new InputStreamReader(System.in);        System.out.println("please input some words, type Enter to exit:");        ic = r.read();        c=(char)ic;        while(c != '\n'){            sbuffer.append(c);            ic = r.read();            c=(char)ic;        }




2.3.2 方法2

回顾一下方法一, 它嵌套两个流, 原始流是System.in(字节流), 还有InputStreamReader(转换流).

但是因为一次只能读取1个字符,它需要用到循环, 还必须建立1个StringBuffer, 略显复杂.


有没有1个方法一次可以读取1个整行呢?

这时我们可以再嵌套1个BufferedReader流.


BufferedReader流是,专门从字符流实现高效缓存读取的一个处理流.


关键它具有readLine()函数, 可以一次读取一整行, 并以字符串形式返回:


readLine

public String readLine()
                throws IOException
读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。
返回:
包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
抛出:
IOException - 如果发生 I/O 错误



例子代码:

        String s = null;        Reader r = new InputStreamReader(System.in);        BufferedReader br = new BufferedReader(r);        System.out.println("please input some words, type Enter to exit:");        s = br.readLine();

可以到虽然这个例子嵌套三层的流.  但是因为避免了循环, 代码反而简洁.




2.4 例子的具体代码:

上面只是分析, 最后把整个程序的代码的例子发出来:


方法1:

import java.io.*;public class GetStrFromKeyBoard{    public static void f(){        String s = null;        System.out.println("please input some words, type Enter to exit:");        try{            s = getStr();        }catch(IOException e){            e.printStackTrace();        }        System.out.println("words your just input is:");        System.out.println(s);     }        public static String getStr() throws IOException{        StringBuffer sbuffer = new StringBuffer(1024);        int ic = 0;        char c;        Reader r = new InputStreamReader(System.in);        ic = r.read();        c=(char)ic;        while(c != '\n'){            sbuffer.append(c);            ic = r.read();            c=(char)ic;        }        r.close();        return sbuffer.toString();       }    }


方法2:

import java.io.*;public class GetStrFromKeyBoard2{    public static void f(){        String s = null;        System.out.println("please input some words, type Enter to exit:");        try{            s = getStr();        }catch(IOException e){            e.printStackTrace();        }        System.out.println("words your just input is:");        System.out.println(s);     }        private static String getStr() throws IOException{        String s = null;        Reader r = new InputStreamReader(System.in);        BufferedReader br = new BufferedReader(r);        s = br.readLine();                r.close();        return s;       }}

输出结果:

gateman@TPEOS Java_1 $ antBuildfile: /media/store1/Studies/Java/java_start/Java_1/build.xmlmain:    [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 2 source files to /media/store1/Studies/Java/java_start/Java_1/build/classes     [java] please input some words, type Enter to exit:Just a test     [java] words your just input is:     [java] Just a testBUILD SUCCESSFULTotal time: 4 seconds








0 0