【第二期】一次学透java.io
java.io是新手学习Java的第一个难点。因为这个package中的东西比较多,也比较复杂,另外加上一些接口太过于面向对象了,更加增大了学习的难度。这一期,我针对这个问题专门探讨一下,通过三篇文章,大家就可以完全地掌握java.io这个包了。
理解流
要掌握java.io,必须要掌握的一个概念就是输入输出流。 数据流是一串连续不断的数据的集合,就象水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。对数据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中的任意长度的数据,但只能先读取前面的数据后,再读取后面的数据。不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。 为什么要有这种抽象呢?我们知道,数据的来源是多种多样的,可能来自文件,也可能来自网络,或者内存,数据可能是有结构的(比如xml),也可能是无结构的,比如简单的文本。所以,如何在语言的层面进行统一的抽象就显得至关重要了。Java中使用了输入输出流这个概念来对所有的数据进行抽象。 根据数据流向的不同,又分为输入流和输出流。输入流是指数据从外部流入当前Java程序,而输出流是指数据从当前的Java程序流出到外部。 在Java中,代表输入流的interface是InputStream,代表输出流的interface是OutputStream。
标准输入输出
命令行参数
从键盘上读入数据,最简捷的方式就是通过命令行参数。可能很多同学在第一次写Java程序的时候,对main方法的参数就会有疑问,不知道它是干啥的。其实这个参数主要就是为了处理命令行参数的,例如:
public class TestIO {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
我们可以通过
java TestIO apple banana pear
来观察一下参数是如何输入到Java程序中的。
标准输入输出错误
大家知道,在控制台程序中,有三个可以进行输入输出的通道,我们通常称之为标准输入,标准输出和标准错误。在C语言中,我们会以stdin, stdout, stderr来代指。在Java中,也有这样的东西,分别是:
java.lang.System
public final class System extends Object{
static PrintStream err;//标准错误流(输出)
static InputStream in;//标准输入(键盘输入流)
static PrintStream out;//标准输出流(显示器输出流)
}
通过查看JDK源代码,可以看到,System.java 里,out是这么定义的:
public final static PrintStream out = null;
可见,out 是一个 static 变量,所以我们才可以使用类名直接引用它。
在Java语言中,所有的输入都被抽象成了输入流(InputStream),所有的输出都被抽象成了输出流(OutputStream)。以OutputStream为例,它的几个子类,PrintStream可以向控制台上输出字节,FileOutputStream可以向文件中写入字节,SocketOutputStream可以向网络连接上写入字节,等等,它们都是OutputStream的子类。
与之相对应的InputStream也有各种子类分别负责不同的功能。只是Output负责向外写,而Input负责向程序里读。
把字节的输入输出抽象成一个连续的流,确实形象了很多。有了IO,我们的程序终于可以与外界进行交互了。例如:
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就得这么写:
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);
}
}
输入
1 2
输入
3
相比起来,C语言的写法就比较简捷:
int main() {
int a, b;
scanf("%d %d", &a, &b);
printf("%dn", a + b);
}
Java为了解决这种数字的输入,就引入了一个叫做Scanner的类,但这个类被视为一个工具类,因为它不是一种流式处理,所以在JDK中,它被放到了java.util包下了。使用Scanner,代码可以化简如下:
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);
}
}
- mysql中创建表实例全析及查询基本操作
- Spring Boot - Profile不同环境配置
- $.each()与$(selector).each()区别详解
- javascript typeof
- php中json_encode
- Java高级进阶:自定义ClassLoader
- 字符串拼接+和concat的区别
- Spring Boot Runner启动器
- Spring Boot自动配置原理、实战
- Spring Aware容器感知技术
- 深入探究frame和bounds的区别以及setbounds使用
- 如何生成二维码过程详解
- hashCode和identityHashCode的区别你知道吗?
- SpringCloud注册中心高可用搭建
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- leetcode - 分割数组的最大值
- leetcode - 除数博弈
- leetcode - 最小路径和
- Javascript中的数据类型
- JAVA 应用日志最佳实践
- 用pageadmin cms系统进行网站制作的经验总结
- 14个Linux系统安全小妙招,总有一招用的上
- CVE-2020-14645:Weblogic远程代码执行复现
- Centos7 安装Mysql-寻找共性-万变不离其宗
- MySQL 入门、安装和客户端管理工具
- MySQL 基本使用(上):DDL 和 DML 语句
- MySQL 基本使用(下):DCL 语句和聚合函数
- 玩转 PhpStorm 系列(二):导航篇
- 带你写出符合Promise/A+规范Promise的源码
- 「R」R Docker 教程