打印流 与
如果要想通过程序实现内容的输出,核心的本质一定要依靠OutputStream类完成,但是OutputStream有一个很大的缺点:数据输出操作功能有限:public void write(byte[] b) throws IOException
,所有的数据一定要转为字节数组后才能输出,如果现在项目中需要输出long、double或者Date,这种情况下就必须将这些数据变为字节的形式来处理,这样的处理其实是非常麻烦的,所以在最初的开发中为了解决此类的重复操作,往往由开发者自行定义一些功能类已简化输出过程。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn.txt";
File file = new File(dirPath);
PrintUtil util = new PrintUtil(new FileOutputStream(file));
util.println("姓名:小强子");
util.print("年龄:");
util.print(78);
}
}
class PrintUtil implements AutoCloseable {//实现数据常用的输出功能
private OutputStream output;//不管现在如何进行输出操作,核心使用的就是OutputStream
public PrintUtil(OutputStream output) {
this.output = output;
}
public void print(String str) {//输出字符串
try {
this.output.write(str.getBytes());//输出
} catch (IOException e) {
e.printStackTrace();
}
}
public void println(String str) {
this.print(str + "\r\n");
}
public void print(long num) {
this.print(String.valueOf(num));
}
public void println(long num) {
this.println(String.valueOf(num));
}
@Override
public void close() throws IOException {
if (output != null) {
output.close();
}
}
}
在整个操作过程之中打印流的设计思想的本质在于:提高已有类的功能,例如:OutputStream是唯一可实现输出的操作标准类,所以应该以其为核心根本,但是这个类的输出的操作功能有限,所以不方便进行输出各个类型的数据,那么就为它做出了一层包装,所以此时采用的设计思想就是“装饰设计模式”。
既然已经发现了原始的OutputStream功能的不足,所以为了解决输出问题,在java.io包中提供了打印流:PrintStream、PrintWriter。
- PrintStream:
public class PrintStream extends FilterOutputStream implements Appendable, Closeable
构造方法:public PrintStream(OutputStream out)
- PrintWriter:
public class PrintWriter extends Writer
构造方法:public PrintWriter(OutputStream out)
下面使用PrintWriter来实现数据的输出操作。
范例:数据输出
import java.io.*;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn.txt";
File file = new File(dirPath);
PrintWriter util = new PrintWriter(new FileOutputStream(file));
util.println("姓名:小强子");
util.print("年龄:");
util.print(78);
util.close();
}
}
从JDK1.5开始,PrintWriter类中追加了格式化输出的操作支持:
public PrintWriter format(String format, Object... args)
范例:格式化输出
import java.io.*;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn.txt";
File file = new File(dirPath);
PrintWriter util = new PrintWriter(new FileOutputStream(file));
String name="张三";
int age=20;
double salary=10000.00;
util.printf("姓名:%s、年龄:%s、月收入:%s",name,age,salary);
util.close();
}
}
比起直接使用OutputStream类,那么使用PrintWriter、PrintStream类的处理操作会更加简单。以后只要是程序进行内容输出时全部使用打印流。
System类对IO的支持
System类是一个系统类,而且是一个非常常用的系统类,而在该类中提供了和输入输出有关的三个常量:
- 标准输出(显示器):
public static final PrintStream out
; - 错误输出:
public static final PrintStream err
; - 标准输入(键盘):public static final InputStream in;
范例:观察输出
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
try {
Integer.valueOf("a");
}catch (Exception e){
System.out.println(e);//白色信息:java.lang.NumberFormatException: For input string: "a"
System.err.println(e);//红色信息:java.lang.NumberFormatException: For input string: "a"
}
}
}
System.out和System.err都是同一种类型的,如果使用的是IntelliJ IDEA在进行System.err输出时会使用红色字体,System.out使用白色字体。
最早设置两个输出的操作的目的:System.out是输出那些希望用户可以看见的信息,System.err是输出那些不希望用户看见的信息,如果有需要,也可以修改输出的位置:
- 修改out的输出位置:
public static void setOut(PrintStream out)
- 修改err的输出位置:
public static void setErr(PrintStream err)
范例:修改System.err位置
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn_err_print.txt";//定义操作的文件
File file = new File(dirPath);
System.setErr(new PrintStream(new FileOutputStream(file)));
try {
Integer.valueOf("a");
}catch (Exception e){
System.out.println(e);
System.err.println(e);//输出到文件中
}
}
}
在System类里面还提供了一个in的常量,而这个常量对应的是标准输入设备键盘的输入处理,可以实现键盘数据输入。
范例:实现键盘输入
import java.io.InputStream;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
InputStream in=System.in;//此时的输入流为键盘输入
System.out.print("请输入信息:");
byte[] data=new byte[1024];//长度限制
int len=in.read(data);
System.out.println("输入的内容为:"+new String(data,0,len));
in.close();
//请输入信息:asdasda
//输入的内容为:asdasda
}
}
但是这样的键盘输入处理本身是有缺陷的:如果现在的长度不足,只能接收部分数据,所以这个输入就有可能需要进行重复的输入流数据接收,而且在接收时还会涉及到输入中文,如果对于中文处理不当,则也有可能造成乱码问题。
类
BufferedReader类提供的是一个缓冲字符输入流的概念,也就是说利用BufferedReader类可以很好的解决输入流数据读取问题,这个类是在最初(JDK1.5之前,1.5后出了一个更很强大的类代替此类)的时候提供的最完善的数据输入的处理,之所以使用这个类来处理,是因为此类中提供有一个重要的方法:
- 读取一行数据:
public String readLine() throws IOException
范例:实现键盘数据输入
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入信息:");
String msg=reader.readLine();
System.out.println("输入的内容为:"+msg);
reader.close();
//请输入信息:123
//输入的内容为:123
}
}
在以后的实际开发中经常会遇到输入数据的情况,所有输入数据的类型都是通过String描述的,那么这样就方便了接收者进行各种处理。
范例:接收整型输入并且验证
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入您的年龄:");
String msg=reader.readLine();
if(msg.matches("\\d{1,3}")){
int age=Integer.valueOf(msg);
System.out.println("您输入的年龄:"+msg);
}else{
System.err.println("输入错误,你输入的内容:"+msg);
}
reader.close();
}
}
现在Java开发由键盘输入数据的情况并不多见,但是作为一些基础的逻辑训练还是可以使用键盘输入数据的,而键盘输入数据的标准做法(JDK1.5之前)就是上面的实现操作。实际开发中所有输入的数据全部为字符串,可以方便验证与进行复杂处理。
类
java.util.Scanner是从JDK1.5之后追加的一个程序类,其主要的目的解决输入流的访问问题的,可以理解为BufferedReader的替代类,在Scanner类中有如下几种操作方法:
- 构造方法:
public Scanner(InputStream source)
- 判断是否有数据:
public boolean hasNext()
- 取出数据:
public String next()
- 设置分隔符:
public Scanner useDelimiter(String pattern)
范例:使用Scanner实现键盘输入字符串
import java.util.Scanner;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的姓名:");
if (sc.hasNext()) {
System.out.println("您输入的姓名:" + sc.next());//换行不算输入
} else {
System.err.println("输入有误,未获取到内容");
}
}
}
范例:使用Scanner实现键盘数字输入
import java.util.Scanner;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的年龄:");
if (sc.hasNextInt()) {//判断是否有整数输入
int age = sc.nextInt();//可以直接获取数字
System.out.println("您输入的年龄:" + age);
}else{
System.err.println("输入有误,未获取到内容");
}
}
}
使用Scanner输入数据还有一个最大的的特点是可以直接利用正则进行验证判断。
范例:输入一个人的生日
import java.util.Scanner;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String birthdayRegex="\\d{4}-\\d{2}-\\d{2}";
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的生日:");
if (sc.hasNext(birthdayRegex)) {
System.out.println("您输入的生日:" + sc.next());//换行不算输入
} else {
System.err.println("输入有误,未获取到内容");
}
}
}
范例:使用Scanner读取文件信息
import java.io.File;
import java.util.Scanner;
public class JavaApiDemo {
public static void main(String[] args) throws Exception {
String dirPath = "/Users/fzc/Documents/mydir/mldn.txt";//定义操作的文件
File file = new File(dirPath);
Scanner sc = new Scanner(file);
sc.useDelimiter("\r\n");//默认以空格作为换行,设置以\r\n为换行符
while (sc.hasNext()) {
System.out.println(sc.next());
}
}
}
现在可以发现Scanner的整体设计要好于BufferedReader,而且要比InputStream类读取更方便。在以后的开发中,如果程序需要输出数据,则要使用打印流,输入数据使用Scanner或BufferedReader。