缓冲输入流是在java中会被大量使用到的工具类,其目的是解决数据的乱码问题。现在最直观的解决方式就是System.in所带来的问题。
如果要进行中文数据的处理,首先想到的是字符流,并且想要完整的处理数据需要到缓冲区,对于缓冲区的操作有两种流:
在给出的缓冲区输入流中有两个,其中最为重要的是BufferedReader,因为在该类中有一个重要的读取方法。
字符缓冲区输入流:BufferedReader
读取一行数据,以分隔符(\n)换行为界,重要的是返回的数据类型是String。
BufferedReader的继承结构:
BufferedReader的构造方法:
但是如果想要使用BufferedReader类来处理System.in的操作就比较麻烦了:因为System.in是InputStream的类型。之前学过一个类:InputStreamReader
public static void main(String[] args) throws Exception {//正常工作一定要通过try catch处理
//System.in是InputStream类的对象
//BufferedReader的构造方法里面需要接收Reader类对象
//利用InputStreamReader将字节流转变为字符流
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入数据");
String str = buf.readLine();//以回车为换行
System.out.println(str);
}
此时输入数据没有长度限制,并且得到的是String型的数据,那么这样就可以实现键盘输入了,但是这种操作意义不大,开发人员和这个没有关系。
一直强调使用BufferedReader是因为他可以实现字符传递
public static void main(String[] args) throws Exception {//正常工作一定要通过try catch处理
//System.in是InputStream类的对象
//BufferedReader的构造方法里面需要接收Reader类对象
//利用InputStreamReader将字节流转变为字符流
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
boolean flag = true;//编写一个循环的逻辑
while(flag) {
System.out.println("请输入数据");
String str = buf.readLine();//以回车为换行
if (str.matches("\\d{1,3}")) {
System.out.println("年龄是:" + Integer.parseInt(str));
flag = false;
} else {
System.out.println("年龄输入错误,请重新输入!");
}
}
}
正是因为可以使用正则验证,所以在开发之中,只要是能够接收类型是String,那么是最方便的。除了可以接收输入信息外,还可以利用缓冲区来进行文件的读取
public static void main(String[] args) throws Exception {//正常工作一定要通过try catch处理
File file = new File("/users/hong/hongs/firsttext.txt");
BufferedReader buf = new BufferedReader(new FileReader(file));
String str = null;
while ((str=buf.readLine())!=null)
{
System.out.println(str);
}
buf.close();
}
与直接使用InputStream类和Reader类相比更加方便,只适用于文件,但是字节数据不是。读取数据不再使用InputStream,就好比输出不直接使用OutputStream一样。
字符缓冲区输出流:BufferedWriter
字节缓冲区输入流:BufferedInputStream
字节缓冲区输出流:BufferedOutputStream
扫描流:Scanner
- Scanner类的主要特点及操作形式
- 利用Scanner解决数据输入流的操作
如果要改进输出功能的不足提供了打印流,又利用BufferedReader类解决了大文本数据的读取操作,但是BufferedReader类有两个问题:
- 读取数据的时候只能按照字符串返回
- 所有的分隔符都是固定的
- 逐渐变为淘汰型工具类
在JDK1.5之后提供java.util.Scanner类,这个类专门解决所有输入流的问题:
构造方法
重要:
public Scanner(InputStream source);
接收一个InputStream类对象
在Scanner里定义了两大组方法:
public boolean hasNext();
public String next();
public boolean hasNext(String pattern);
public String next(String pattern);
两组对应操作
第一个是判断是否有指定数据:public boolean hasNextXXX();
第二个是取出数据:public String nextXXX();
以键盘输入数据为例:
public static void main(String[] args) throws Exception {//正常工作一定要通过try catch处理
Scanner scan = new Scanner(System.in);
System.out.println("请输入内容:");
if(scan.hasNext())
{
System.out.println(scan.next());
}
scan.close();
}
与BufferedReader相比更加容易,操作更加直观。
但是需要提醒的是,如果现在输入的是字符串,是否存在有hasNext()
的方法意义不大,但是 如果是其他类型就有用了,但是为了操作的统一性,都加上hasNext()
判断。
hasNext()和next()中可以直接跟正则表达式
在Scanner类里面由于接收的类型是InputStream,所以此时依然可以设置一个文件的数据流,但在进行文件读取的时候,需要考虑到分隔符问题。
很重要的方法(必须记住)
public Scanner useDelimiter(String pattern);
//设置分隔符
public static void main(String[] args) throws Exception {//正常工作一定要通过try catch处理
Scanner scan = new Scanner(new FileInputStream(new File("/users/hong/hongs/firsttext.txt")));
scan.useDelimiter("\n");
while(scan.hasNext())
{
System.out.println(scan.next());
}//默认按照换行和空格进行读取的
scan.close();
}
现在使用Scanner读取数据的时候要比BufferedReader要简单一些。
以后在开发中如果程序输出数据使用打印流,输入数据使用Scanner(如果发现Scanner不好用了,使用BufferedReader)
总结
InputStream类的功能不足已经被Scanner解决了
Reader类的功能不足已经被BufferedReader解决了
OutputStream的功能不足被PringStream解决了
Writer类的功能不足被PrintWriter解决了
对象序列化
- 对象序列化的意义以及实现
- 了解对象输入、输出流的使用
- 理解transient关键字
对象序列化(重点)
所谓的对象序列化指的就是将保存在内存中的对象数据转换为二进制数据流进行传输的操作。但是并不是所有类的对象都可以进行序列化,如果要被序列化的对象,那么其所在的类一定要实现java.io.Serializable接口。但是这个接口里面并没有任何方法存在,因为这是一个标识接口,表示一种能力。
Java一共两个标识接口:
Clonable:用于对象克隆上
Serializable:用在对象序列化上
class Book implements Serializable{//表示此类对象可以被序列化
private String title;
private double price;
public Book(String title,double price)
{
this.title=title;
this.price=price;
}
public String toString()
{
return "书名"+this.title+"价格:"+this.price;
}
}
实现了Serializable接口就可以实现二进制传输了。
实现序列化与反序列化
由于现在只有单机程序,所以下面将对象序列化到文件里,随后通过文件反序列化到程序之中。如果想实现这样的操作,需要下面两个类的支持:
- 序列化类:
ava.io.ObjectOutputStream
;将对象变为指定格式的二进制数据 - 反序列化操作类:
java.io.ObjectInputStream
,可以将序列化的对象转换回对象内容
实现序列化对象操作:ObjectOutputStream
- 构造方法:
public ObjectOutputStream(OutputStream out)throws IOException;
- 输出对象:
public final void writeObject(Object obj)throws IOException
参数是Object,意味着所有类都可以被序列化。
class Book implements Serializable{//表示此类对象可以被序列化
private String title;
private double price;
public Book(String title,double price)
{
this.title=title;
this.price=price;
}
public String toString()
{
return "书名"+this.title+"价格:"+this.price;
}
}
public class Main {
public static void main(String[] args) throws Exception {//正常工作一定要通过try catch处理
ser();
}
public static void ser()throws Exception{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("/users/hong/hongs/firsttext.txt")));
out.writeObject(new Book("Java开发",79.8));//序列化对象
out.close();
}
}
实现对象的反序列化操作:ObjectInputStream
构造方法:
public ObjectInputStream(InputStream in)throws IOException;
读取方法:
public final Object readObject()throws IOException,
ClassNotFoundException
class Book implements Serializable{//表示此类对象可以被序列化
private String title;
private double price;
public Book(String title,double price)
{
this.title=title;
this.price=price;
}
public String toString()
{
return "书名"+this.title+"价格:"+this.price;
}
}
public class Main {
public static void main(String[] args) throws Exception {//正常工作一定要通过try catch处理
// ser();
dser();
}
public static void ser()throws Exception{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("/users/hong/hongs/firsttext.txt")));
out.writeObject(new Book("Java开发",79.8));//序列化对象
out.close();
}
public static void dser()throws Exception{
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("/users/hong/hongs/firsttext.txt")));
Object obj = in.readObject();
Book book = (Book) obj;
System.out.println(book);
in.close();
}
}
在以后的实际开发中,会由容器帮助用户自动完成以上操作。只需实现Serializable接口即可。
transient关键字
虽然以上实现了对象序列化,但是会发现序列化操作是将整个对象的所有属性内容进行了一个保存,如果说现在某些属性的内容不需要被保存,就需要transient关键字来定义
private transient String title;
此时title属性不会被序列化。但是大部分情况下不需要使用这个关键字,但还是需要掌握的。
总结
对象序列化本身就是一个简单的概念,因为在开发中使用很广泛,所以要清楚Serializable接口的使用,但是要清楚不是所有的类都需要序列化。只有需要传输的对象所在的类才需要此类操作