输入与输出支持
如果现在想要通过程序实现内容的输出,那么核心的本质一定要通过OutputStream类完成,该类最大的缺点是数据输出功能有限。(public void write(byte[] b) throws IOException
),所有的数据一定要转为字节数组后才可以输出,假设说现在项目中可能输出的是long、double、Date,再这样的情况下就必须将这些数据变为字节的形式来处理,这样的处理是比较麻烦的,最初时为了解决此类的重复操作,往往会由开发者自行定义一些功能类简化输出过程。
打印流
打印流设计思想
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
class PrintUtil implements AutoCloseable{
//实现常用数据输出
private OutputStream output; //不管现在如何操作,核心就是使用OutputStream
public PrintUtil(OutputStream output) {
//由外部决定输出的位置
this.output = output;
}
public void println(long num) {
this.println(String.valueOf(num));
}
public void print(long num) {
this.print(String.valueOf(num));
}
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");
}
@Override
public void close() throws Exception {
this.output.close();
}
}
public class Introduce {
public static void main(String[] args) throws Exception {
File file = new File("C:\\Project\\Java_study\\src\\文件\\test.txt");
PrintUtil pu = new PrintUtil(new FileOutputStream(file));
pu.println("name:lyz");
pu.print("age:");
pu.print(78);
pu.close();
}
}
整个操作过程中打印流的设计思想的本质在于:提高已有类的功能,例如:OutputStream是唯一可以实现输出的操作标准类,应该以其为核心根本,但是这个类输出的操作功能有限,所以不方便进行输出各个数据类型,那么就为它作出一层包装,所以此时采用的设计思想就是“装饰设计模式”。
但是既然所有的开发者都已经发现了原始中的OutputSteam功能的不足,设计者也一定可以发现,所以为了解决输出问题在java.io包里面提供有打印流:PrintStream、PrintWriter。
PrintStream | PrintWriter |
---|---|
public class PrintStream extends FilterOutputStrem implements Appendable,Closeable | public class PrintWriter extends Writer |
构造:public PrintStream(OutputStream out) | 构造:public PrintWriter(OutputStream out/Writer out) |
使用PrintWriter实现数据输出操作
数据输出
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class Introduce {
public static void main(String[] args) throws Exception {
File file = new File("C:\\Project\\Java_study\\src\\文件\\test.txt");
PrintWriter pu = new PrintWriter(new FileOutputStream(file));
pu.println("name:33333");
pu.print("age:");
pu.print(78);
pu.close();
}
}
从JDK1.5开始PrintWriter类里面追加有格式化输出的操作支持:public PrintWriter printf(String format,Object... args);
格式化输出
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class Introduce {
public static void main(String[] args) throws Exception {
File file = new File("C:\\Project\\Java_study\\src\\文件\\test.txt");
PrintWriter pu = new PrintWriter(new FileOutputStream(file));
String name = "ly";
int age = 18;
double salary = 7812.23;
pu.printf("name:%s,age:%d,salary:%9.2f", name,age,salary);
pu.close();
}
}
比起直接用OutputStream类,使用PrintWriter、PrintStream类的处理操作会更加简单。以后只要是程序进行内容输出的时候全部使用打印流。
System类对IO的支持
System是一个系统类,而且是一个从头到尾一直在使用的系统类,在该类中提供有三个常量:
- 标准输出(显示器):
public static final PrintStream out;
- 错误输出:
public static final PrintStream err;
- 标准输入(键盘):
public static final InputStream in;
System.out和System.err都是同一种类型的,如果现在使用的是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 System_IO {
public static void main(String[] args) throws Exception {
System.setErr(new PrintStream(new FileOutputStream(new File("C:\\Project\\Java_study\\src\\文件\\test.txt"))));
try {
Integer.parseInt("a");
} catch (Exception e) {
System.out.println(e);
System.err.println(e); //输出到文件
}
}
}
在System类中还提供一个in常量,这个常量对应的是标准输入设备键盘的输入处理,可以实现键盘数据输入。
实现键盘输入
import java.io.InputStream;
public class System_IO {
public static void main(String[] args) throws Exception {
InputStream input = System.in;
System.out.println("输入信息:");
byte[] data = new byte[1024];
int len = input.read(data);
System.out.println(new String(data,0,len));
}
}
这样的键盘输入处理本身是有缺陷的:如果现在的接收数组长度不足,那么只能够接收部分数据,所以这个输入需要重复输入流数据接收。而且还有可能会牵扯到输入中文的情况,若对于中文处理不当,有可能出现乱码的问题。
BufferedReader缓冲输入流
BufferedReader类提供的是一个缓冲字符输入流的概念,也就是利用BufferedReader类可以很好地解决输入流数据的读取问题,这个类是在最初的时候提供的最完善的输入的处理(JDK1.5之前,1.5之出现了更强大的类),之所以使用这个类,是因为这个类中提供一个重要的方法:
- 读取一行数据:
public String readLine() throws IOException;
import java.io.InputStreamReader;
public class BufferedReader {
public static void main(String[] args) throws Exception {
java.io.BufferedReader input = new java.io.BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入信息:");
String msg = input.readLine(); //接收输入
System.out.println("输入内容:"+ msg);
}
}
以后实际开发过程中经常会遇到输入数据的情况,而所有输入数据的类型都是通过String描述的,这样方便了接收者进行各种处理。
接受整型输入并验证
import java.io.InputStreamReader;
public class BufferedReader {
public static void main(String[] args) throws Exception {
java.io.BufferedReader input = new java.io.BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入age:");
String msg = input.readLine(); //接收输入
if(msg.matches("\\d+{1,3}")) {
//是否由数字组成
int age = Integer.parseInt(msg);
System.out.println("age:"+age);
} else {
System.out.println("输入错误!");
}
}
}
对于现代的Java开发由键盘输入数据的情况不多,键盘输入的标准做法(JDK1.5)就是上面的实现操作,实际开发中所有输入数据全部都是字符串,方便用户进行验证和字符串的复杂处理。
Scanner扫描流
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 Scanner_Study {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("input age:");
if(scan.hasNextInt()) {
System.out.println("age:"+ scan.nextInt());
} else {
System.out.println("get out!");
}
scan.close();
}
}
使用Scanner输入字符串
import java.util.Scanner;
public class Scanner_Study {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("msg:");
if(scan.hasNext()) {
System.out.println("msg:"+ scan.next());
} else {
System.out.println("get out!");
}
scan.close();
}
}
使用Scanner输入数据还有一个最大的特点可以直接利用正则进行验证判断。
输入一个生日进行验证
import java.text.SimpleDateFormat;
import java.util.Scanner;
public class Scanner_Study {
public static void main(String[] args) throws Exception {
Scanner scan = new Scanner(System.in);
System.out.println("birthday:");
if(scan.hasNext("\\d{4}-\\d{2}-\\d{2}")) {
// String str = scan.next();
System.out.println("msg:"+ new SimpleDateFormat("yyyy-MM-dd").parse(scan.next()));
} else {
System.out.println("get out!");
}
scan.close();
}
}
可以发现Scanner的整体设计好于BufferedReader,而且要比直接使用InputStream要更为方便。如果采用InputStream读取一个文本文件中所有内容信息就必须依靠内存输出流进行临时数据保存还需判断内容是否是换行。
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Scanner;
public class Scanner_Study {
public static void main(String[] args) throws Exception {
Scanner scan = new Scanner(new File("C:\\Project\\Java_study\\src\\文件\\test.txt"));
scan.useDelimiter("\n"); //设置读取分隔符
while(scan.hasNext()) {
System.out.println(scan.next());
}
scan.close();
}
}
以后开发中程序需要输出数据一定使用打印流(PrintWriter),输入数据使用Scanner或BufferedReader。