前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【第二期】一次学透java.io

【第二期】一次学透java.io

作者头像
海纳
发布2018-03-02 14:48:12
7580
发布2018-03-02 14:48:12
举报
文章被收录于专栏:海纳周报

java.io是新手学习Java的第一个难点。因为这个package中的东西比较多,也比较复杂,另外加上一些接口太过于面向对象了,更加增大了学习的难度。这一期,我针对这个问题专门探讨一下,通过三篇文章,大家就可以完全地掌握java.io这个包了。

理解流

要掌握java.io,必须要掌握的一个概念就是输入输出流。 数据流是一串连续不断的数据的集合,就象水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。对数据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中的任意长度的数据,但只能先读取前面的数据后,再读取后面的数据。不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。 为什么要有这种抽象呢?我们知道,数据的来源是多种多样的,可能来自文件,也可能来自网络,或者内存,数据可能是有结构的(比如xml),也可能是无结构的,比如简单的文本。所以,如何在语言的层面进行统一的抽象就显得至关重要了。Java中使用了输入输出流这个概念来对所有的数据进行抽象。 根据数据流向的不同,又分为输入流和输出流。输入流是指数据从外部流入当前Java程序,而输出流是指数据从当前的Java程序流出到外部。 在Java中,代表输入流的interface是InputStream,代表输出流的interface是OutputStream。

标准输入输出

命令行参数

从键盘上读入数据,最简捷的方式就是通过命令行参数。可能很多同学在第一次写Java程序的时候,对main方法的参数就会有疑问,不知道它是干啥的。其实这个参数主要就是为了处理命令行参数的,例如:

代码语言:javascript
复制
public class TestIO {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
    }
}

我们可以通过

代码语言:javascript
复制
java TestIO apple banana pear

来观察一下参数是如何输入到Java程序中的。

标准输入输出错误

大家知道,在控制台程序中,有三个可以进行输入输出的通道,我们通常称之为标准输入,标准输出和标准错误。在C语言中,我们会以stdin, stdout, stderr来代指。在Java中,也有这样的东西,分别是:

代码语言:javascript
复制
java.lang.System   
public final class System  extends Object{   
   static  PrintStream  err;//标准错误流(输出)  
   static  InputStream  in;//标准输入(键盘输入流)  
   static  PrintStream  out;//标准输出流(显示器输出流)  
}  

通过查看JDK源代码,可以看到,System.java 里,out是这么定义的:

代码语言:javascript
复制
public final static PrintStream out = null;

可见,out 是一个 static 变量,所以我们才可以使用类名直接引用它。

在Java语言中,所有的输入都被抽象成了输入流(InputStream),所有的输出都被抽象成了输出流(OutputStream)。以OutputStream为例,它的几个子类,PrintStream可以向控制台上输出字节,FileOutputStream可以向文件中写入字节,SocketOutputStream可以向网络连接上写入字节,等等,它们都是OutputStream的子类。

与之相对应的InputStream也有各种子类分别负责不同的功能。只是Output负责向外写,而Input负责向程序里读。

把字节的输入输出抽象成一个连续的流,确实形象了很多。有了IO,我们的程序终于可以与外界进行交互了。例如:

代码语言:javascript
复制
        byte[] buf = new byte[512];
        System.out.println("hey, may I have your name, please? ");
        int n = 0;
        try {
            n = System.in.read(buf);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.print("hello, ");
        System.out.write(buf, 0, n);

前三个字节是一组,通过UTF-8(我们会在后续的课程中陆续介绍编码的知识)的解码,可以得到前三个字节代表的十进制数是28023,这刚好就是中文字符“海”字的 unicode 码。可见,直接的字节操作对非ascii的字符会比较麻烦。例如,程序读入一个名字,想判断这个名字的姓氏是否为李,如果是字节的操作,我们就得先把读到的这些字节,解码到 unicode,或者反过来,把“李”编码为UTF-8再进行比较。这显然太麻烦了,编解码这么机械的工作,干嘛不让机器替我们做呢?

基于这个想法,Java引入了一个可以把字节流转成字符流的适配器——InputStreamReader。请继续观看下一篇文章,适配器模式。

Scanner

文章的最后,我还想额外提一下Scanner类。这是一个用于输入的辅助类,是从Java1.5开始引入的。在那之前,如果我想从标准输入里读两个数,并把它们的和打出来。用Java就得这么写:

代码语言:javascript
复制
public class TestIO {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = br.readLine();
        String[] ss = s.split(" ");
        int a = Integer.parseInt(ss[0]);
        int b = Integer.parseInt(ss[1]);
        System.out.print(a + b);
    }
}

输入

代码语言:javascript
复制
1 2

输入

代码语言:javascript
复制
3

相比起来,C语言的写法就比较简捷:

代码语言:javascript
复制
int main() {
  int a, b;
  scanf("%d %d", &a, &b);
  printf("%d\n", a + b);
}

Java为了解决这种数字的输入,就引入了一个叫做Scanner的类,但这个类被视为一个工具类,因为它不是一种流式处理,所以在JDK中,它被放到了java.util包下了。使用Scanner,代码可以化简如下:

代码语言:javascript
复制
public class TestIO {
    public static void main(String[] args) throws IOException {
        Scanner cin = new Scanner(System.in);
        int a = cin.nextInt();
        int b = cin.nextInt();
        System.out.println(a + b);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HinusWeekly 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 理解流
  • 标准输入输出
    • 命令行参数
      • 标准输入输出错误
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档