1 打印流
如果现在要想通过程序实现内容的输出,核心的本质一定要依靠OutputStream类完成,但是OutputStream有一个最大的缺点,这个类中的数据输出操作功能有限:public void write(byte[] b) throws IOException
,所有的数据一定要转换为字节数组才可以输出,于是假设说现在你的项目里面可能输出的是long、double、Date,在这样的情况下就必须将这些数据变为字节的形式来处理,这样的处理一定是非常麻烦的,所以在开发之中最初的时候为了解决此类的重复操作,往往会由开发者自行定义一些功能类以简化输出过程。
范例:打印流的设计思想
package cn.victor.demo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
class PrintUtil implements AutoCloseable{
private OutputStream output;
public PrintUtil(OutputStream output) {
this.output = output;
}
public void print(String str) {
try {
this.output.write(str.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void print(int num) {
this.print(String.valueOf(num));
}
public void println(String str) {
this.print(str + "\r\n");
}
@Override
public void close() throws Exception {
this.output.close();
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
File file = new File("d:" + File.separator + "hy" + File.separator + "love.txt");
if( file.getParentFile().exists() ) {
file.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(file);
PrintUtil pu = new PrintUtil(output);
pu.println("hhy big fool!");
pu.print("20");
pu.close();
}
}
在整个的操作过程之中打印流的设计思想的本质在于:提高已有类的功能,例如:OutputStream是唯一可以实现输出的操作标准类,所以应该以其为核心根本,但是这个类输出的操作功能有限,所以不方便进行输出各个数据类型,那么就为它做出了一层包装,所以此时采用的设计思想就是“装饰设计模式”。
但是既然所有的开发者都已经发现了原始中的OutputStream功能的不足,设计者也一定可以发现,所以为了解决输出问题,在java.io包里面提供有打印流:PrintStream、PrintWriter。
下面使用PrintWriter来实现数据的输出操作。
范例:数据输出
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
File file = new File("d:" + File.separator + "hy" + File.separator + "love.txt");
if( file.getParentFile().exists() ) {
file.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(file);
PrintWriter pu = new PrintWriter(output);
pu.println("hhy big fool!");
pu.print("20");
pu.close();
}
}
从JDK 1.5开始PrintWriter类里面追加有格式化输出的操作支持:
范例:格式化输出
package cn.victor.demo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
File file = new File("d:" + File.separator + "hy" + File.separator + "love.txt");
if( file.getParentFile().exists() ) {
file.getParentFile().mkdirs();
}
OutputStream output = new FileOutputStream(file);
PrintWriter pu = new PrintWriter(output);
pu.printf("name: %s, age: %d, salary: %9.2f", "hhy", 20, 938.23123);
pu.close();
}
}
比起直接使用OutputStream类,那么使用PrintWriter、PrintStream类的处理操作会更加的简单。以后只要是程序进行内容输出的时候全部使用打印流。
2 System类对IO的支持
System类是一个系统类,而且是一个从头到尾一直都在使用的系统类,而在这个系统类之中实际上提供有三个常量:
(1)标准输出(显示器):public static final PrintStream out
(2)错误输出:public static final PrintStream err
(3)标准输入(键盘):public static final InputStream in
范例:观察输出
package cn.victor.demo;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
try {
Integer.parseInt("a");
}catch(Exception e) {
System.out.println(e);
System.err.println(e);
}
}
}
System.out和System.err都是同一种类型的,如果现在使用的是Eclipse则在使用System.err输出的时候会使用红色字体,System.out会使用黑色字体。
最早设置两个输出的操作是有目的的:System.out是输出那些希望用户可以看见的信息、System.err是输出奈雪儿不希望用户看见的信息,如果有需要也可以修改输出的位置:
(1)修改out的输出位置:public static void setOut(PrintStream out)
(2)修改err的输出位置:public static void setErr(PrintStream err)
package cn.victor.demo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
System.setErr(new PrintStream(new FileOutputStream(new File("d:" + File.separator + "hy" + File.separator + "log.txt"))));
try {
Integer.parseInt("a");
}catch(Exception e) {
System.out.println(e);
System.err.println(e);
}
}
}
在System类里面还提供有一个in的常量,而这个常量对应的是标准输入设备键盘的输入处理,可以实现键盘数据输入。
范例:实现键盘输入
package cn.victor.demo;
import java.io.InputStream;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
InputStream input = System.in;
int len = -1;
byte[] content = new byte[1024];
while((len = input.read(content)) != -1) {
System.out.println(new String(content, 0, len));
}
}
}
但是这样的键盘输入处理本身是有缺陷的:如果你现在的长度不足,那么只能够接收部分数据,所以输入就有可能进行重复的输入流数据接收,而且还有可能在接收的时候还有可能会牵扯到输入中文的情况,如果对于中文的处理不当,则也有可能造成乱码问题。
3 BufferedReader缓冲输入流
BufferedReader类提供的是一个缓冲字符输入流的概念,也就是说利用BufferedReader类可以很好的解决输入流数据的读取问题,这个类是在最初的时候提供的最完善的数据输入处理(JDK 1.5之前,JDK 1.5之后出了一个功能更强大的类代替此类),之所有使用这个类来处理,是因为这个类之中提供有一个重要方法:
(1)读取一行数据:public String readLine() throws IOException
将利用这个类实现键盘输入数据的标准化定义。
范例:实现键盘数据输入
package cn.victor.demo;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String str = input.readLine();
System.out.println(str);
}
}
在以后实际的开发过程之中经常会遇见输入数据的情况,而所有输入数据的类型都是通过String描述的,那么这样就方便了接收者进行各种处理。
范例:接受整形输入并且验证
package cn.victor.demo;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
System.out.println("please input your age: ");
String str = input.readLine();
if( str.matches("\\d+")) {
System.out.println("your age is " + Integer.parseInt(str));
}else {
System.out.println("Error input");
}
}
}
对于现代的Java开发由键盘输入的情况并不多了,但是作为一些基础的逻辑训练还是可以使用键盘输入数据的,而键盘输入数据的标准做法(JDK 1.5之前)就是上面的实现操作。实际开发之中所有输入的数据全部都是字符串,这样可以方便用户验证与进行字符串的复杂处理。
4 Scanner扫描流
java.util.Scanner是从JDK 1.5之后追加的一个程序类,其主要的目的是为了解决输入流的访问问题,可以理解为BufferedReader的替代功能类,在Scanner类里面有如下几种核心操作方法:
(1)构造方法:public Scanner(InputStream source)
(2)判断是否有数据:public boolean hasNext()
(3)取出数据:public String next()
(4)设置分隔符:public Scanner useDelimiter(String pattern)
范例:使用Scanner实现键盘数据输入
package cn.victor.demo;
import java.util.Scanner;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
Scanner scan = new Scanner(System.in);
if(scan.hasNext()) {
String str = scan.next();
System.out.println(str);
}
}
}
此时可以明显的感受到Scanner的处理会更加简单。
范例:输入一个整数
package cn.victor.demo;
import java.util.Scanner;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
Scanner scan = new Scanner(System.in);
if(scan.hasNextInt()) {
int num = scan.nextInt();
System.out.println(num);
}
}
}
使用Scanner输入数据还有一个最大的特点是可以直接利用正则进行验证判断。
范例:输入一个人的生日(yyyy-MM-dd)
package cn.victor.demo;
import java.text.SimpleDateFormat;
import java.util.Scanner;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
Scanner scan = new Scanner(System.in);
if(scan.hasNext("\\d{4}-\\d{2}-\\d{2}")) {
String str = scan.next("\\d{4}-\\d{2}-\\d{2}");
System.out.println(new SimpleDateFormat("yyyy-MM-dd").parse(str));
}
}
}
现在可以发现Scanner的整体设计要好于BufferedReader,而且要比直接使用InputStream类读取要方便。例如,现在要读取一个文本文件中的所有内容信息,如果采用的是InputStream类,那么就像必须依靠内容输出流进行临时数据的保存,随后还需要判断读取的内容是否是换行。
范例:使用Scanner读取
package cn.victor.demo;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Scanner;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception{
Scanner scan = new Scanner(new File("d:" + File.separator + "hy" + File.separator + "project02" + File.separator + "Sqlist.h"));
scan.useDelimiter("\n");
while(scan.hasNext()) {
System.out.println(scan.next());
}
}
}
在以后的开发过程之中,如果程序需要输出数据一定使用打印流,输入数据使用Scanner(BufferedReader)。