JavaIO——System对IO的支持、序列化
1、系统类对IO的支持
在我们学习PriteWriter、PrintStream里面的方法print、println的时候是否观察到其与我们之前一直使用的系统输出很相似呢?其实我们使用的系统输出就是采用IO模式完成的。
在System中定义了三个操作的常量:
a、标准输出:(System.out) public final static PrintStream out
b、错误输出:(System.err) public final static PrintStream err
c、标准输入:(System.in) public final static InputStream in
(1)系统输出
out和err常量都为系统输出,都是PrintStream类对象。
两者之间的区别在于:out输出的内容是希望用户看到的内容而err输出的是不希望用户看到的。其中err只是一个保留的属性,现在几乎用不到。
由其结构可以看出System.out是PrintStream的实例化对象,而由类图可得PrintStream是OutputStream的子类,所以可以直接使用System.out直接为OutputStream实例化,这个时候的OutputStream输出的位置将变为屏幕。
-
/*
-
* 系统输出
-
* */
-
public class Test3{
-
public static void main(String[] args) throws IOException {
-
OutputStream outputStream = System.out;
-
outputStream.write("你好!".getBytes());
-
}
-
}
(2)系统输入
与前面两者不同的是System.in是InputStream的对象。而这种输入操作是指用户通过键盘输入(用户输入)。Java本身并没有直接的用户输入,所以要想实现这样的操作,还得借助java.io模式来完成。
-
/*
-
* 系统输入
-
* */
-
public class Test3{
-
public static void main(String[] args) throws IOException {
-
InputStream inputStream = System.in;
-
byte[] data = new byte[1024];
-
System.out.println("请输入:");
-
//将数据读取到字节数组中
-
int temp = inputStream.read(data);
-
System.out.println("输出为:"+new String(data,0,temp));
-
inputStream.close();
-
}
-
}
通过程序我们可以发现:当用户输入信息时程序需要暂停执行,这是因为程序进入了阻塞状态,直至我们输入操作完成后按回车,程序才可以继续向下进行。且以上程序中我们是采用开辟固定长度的字节数组,当我们输入的字节大于该固定长度时就会出现读取部分数据的结果。这是因为一次读取不完造成的结果。所以我们将引入内存流对其进行改进,先将这些数据保存在内存流中然后一次性进行取出。
-
/*
-
* 输入字节数大于开辟数组的大小
-
* */
-
public class Test3{
-
public static void main(String[] args) throws IOException {
-
InputStream inputStream = System.in;
-
byte[] data = new byte[16];
-
System.out.println("请输入:");
-
//将数据读取到字节数组中
-
int temp = inputStream.read(data);
-
System.out.println("输出为:"+new String(data,0,temp));
-
inputStream.close();
-
}
-
}
-
/*
-
* 内存流进行改进操作
-
* */
-
public class Test3{
-
public static void main(String[] args) throws IOException {
-
InputStream inputStream = System.in;
-
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-
byte[] data = new byte[16];
-
System.out.println("请输入:");
-
int temp = 0;
-
while((inputStream.read(data)) != -1) {
-
//保存数据到内存输出流中
-
byteArrayOutputStream.write(data,0,temp);
-
//用户判断输入结束
-
if(temp < data.length) {
-
break;
-
}
-
break;
-
}
-
inputStream.close();
-
byteArrayOutputStream.close();
-
System.out.println("输出为:"+new String(byteArrayOutputStream.toByteArray()));
-
}
-
}
由此我们可以发现虽然实现了用键盘输入数据的功能,但是使得整体的实现逻辑过于混乱,所以说java提供的System.in并不好用,还要结合内存流来完成,复杂度很高。
如果要想在IO中进行中文的处理,最好的做法是将所有输入的数据保存在一起再处理,这样才可以保证不出现乱码。
由此我们可以引入java提供的两种输入流:
(3)输入流(BufferedReader和Scanner)
A、BufferedReader类
BufferReader类是一个缓冲输入流,且是字符流的操作对象。
缓冲流也可分为两类:字节缓冲流((BufferedInputStream)和字符缓冲流(BufferedReader)。
我们之所以选择BufferReader类操作,是因为在该类中提供有如下方法(读取一行数据)
public String readLine() throws IOException这个方法可以直接读取一行数据,以回车为换行符。
但是当我们观察BufferReader类及其构造函数:
public class BufferedReader extends Reader
public BufferedReader(Reader in)而我们使用的System.in是InputStream的子类和Reader并没有直接的关系,所以我们需要建立他们之间的联系:利用InputStreamReader类。
-
/*
-
* 利用BufferedReader类实现键盘输入
-
* */
-
public class Test3{
-
public static void main(String[] args) throws IOException {
-
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
-
System.out.println("请输入:");
-
//默认使用回车换行,默认的换行模式也是BufferReader的缺点
-
String string = bufferedReader.readLine();
-
System.out.println("输出为:"+string);
-
}
-
}
使用以上形式实现的键盘输入还有一个大特点,由于接收的数据类型为String,可以使用String类的各种操作进行数据处理并且可以变为各种常见数据类型。且该类在jdk1.5后被java.util.Scanner所替代。
B、Scanner类
Scanner类在java.util包下;
打印流解决的是OutputStream类的缺陷,BefferedReader解决的是InputStream类的缺陷。而Scanner解决的是 BefferedReader类的缺陷(替换了BefferedReader类)
Scanner是一个专门进行输入流处理的程序类,利用这个类可以方便处理各种数据类型,同时也可以直接结合正则表达式进行各项处理,在这个类中主要关注以下方法:
1. 判断是否有指定类型数据: public boolean hasNextXxx()
2. 取得指定类型的数据: public 数据类型 nextXxx() 只要有数据输入,遇到第一个空格、回车、制表符都会终止读取数据。
public 数据类型 nextLine()只以回车符终止(遇到空格、制表符仍然继续进行读取)
3. 定义分隔符:public Scanner useDelimiter(Pattern pattern)
4. 构造方法:public Scanner(InputStream source)
-
/*
-
* 使用Scanner类实现数据输入
-
* */
-
public class Test3{
-
public static void main(String[] args) {
-
Scanner scanner = new Scanner(System.in);
-
System.out.println("请输入:");
-
//有输入内容不判断空字符串
-
if(scanner.hasNext()) {
-
//遇到空格、制表符、回车均停止数据的读取
-
// System.out.println("输入内容为:"+scanner.next());
-
//只有遇到回车才停止数据的读取
-
System.out.println("输入内容为:"+scanner.nextLine());
-
}
-
scanner.close();
-
}
-
}
通过上述运行结果我们可以验证nextXXX()方法进行相应数据类型数据的读取时,只要遇到空格就停止读取数据。
最为重要的是,Scanner可以对接收的数据类型使用正则表达式判断。
-
/*
-
* 自定义格式输出
-
* */
-
public class Test3{
-
public static void main(String[] args) {
-
Scanner scanner = new Scanner(System.in);
-
System.out.println("请输入出生日期:");
-
if(scanner.hasNext("\\d{4}-\\d{2}-\\d{2}")) {
-
String string = scanner.nextLine();
-
System.out.println("出生日期为:"+string);
-
}else {
-
System.out.println("输入格式错误");
-
}
-
}
-
}
使用Scanner本身能够接收的是一个InputStream对象,那么也就意味着可以接收任意输入流,例如:文件输入流;Scanner完美的替代了BufferedReader,而且更好的实现了InputStream的操作。
-
/*
-
* 使用Scanner操作文件
-
* */
-
public class Test3{
-
public static void main(String[] args) throws FileNotFoundException {
-
String singal = File.separator;
-
Scanner scanner = new Scanner(new FileInputStream(
-
new File("C:"+singal+"Users"+singal+"lenovo"+singal+"Desktop"+singal+"Test2.txt")));
-
//自定义分隔符
-
scanner.useDelimiter("\n");
-
while(scanner.hasNext()) {
-
System.out.println(scanner.next());
-
}
-
scanner.close();
-
}
-
}
所以以后除了二进制文件拷贝的处理之外,只要是针对程序的信息输出都是用打印流(PrintStream、 PrintWriter),信息输出使用Scanner。
2、序列化
(1)概念
所谓的序列化指的是将程序中的属性以二进制流的形式在网络上传输或者保存在文件中。
可进行序列化的要求:并不意味着所有类的对象都可以被序列化,需要被序列化的类对象往往需要传输使用,同时这个类必须实现 java.io.Serializable接口。这个接口并没有任何的方法定义,只是一个标识而已。
(2)序列化与反序列化的实现
如果要想实现序列化与反序列化的对象操作,在java.io包中提供有两个处理类:ObjectOutputStream、ObjectInputStream
-
/*
-
* 实现序列化与反序列化
-
* */
-
//定义要被序列化的类
-
class Student implements Serializable{
-
private String name = "lemon";
-
//要使用包装类
-
private Integer age = 20;
-
Student(String name, Integer age) {
-
super();
-
this.name = name;
-
this.age = age;
-
}
-
//覆写toString方法
-
public String toString() {
-
return "Student [name=" + name + ", age=" + age + "]";
-
}
-
-
}
-
public class Test3{
-
static String singal = File.separator;
-
public static final File FILE = new File(
-
"C:"+singal+"Users"+singal+"lenovo"+singal+"Desktop"+singal+"Test2.txt");
-
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
-
achieveSer(new Student("lemon",10));
-
opsiteSer();
-
}
-
//实现序列化操作
-
public static void achieveSer(Object object) throws FileNotFoundException, IOException {
-
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(FILE));
-
objectOutputStream.writeObject(object);
-
objectOutputStream.close();
-
}
-
//反序列化操作
-
public static void opsiteSer() throws FileNotFoundException, IOException, ClassNotFoundException {
-
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(FILE));
-
System.out.println(objectInputStream.readObject());
-
objectInputStream.close();
-
}
-
}
实现序列化:
实现反序列化:
(3)transient关键字
由于Serializable默认会将对象中所有属性进行序列化保存,如果现在某些属性不希望被保存了,那么就可以 使用transient关键字。
修改上述代码(在age属性上加transient关键字)
-
//定义要被序列化的类
-
class Student implements Serializable{
-
private String name = "lemon";
-
//要使用包装类
-
private transient Integer age = 20;
-
Student(String name, Integer age) {
-
super();
-
this.name = name;
-
this.age = age;
-
}
-
//覆写toString方法
-
public String toString() {
-
return "Student [name=" + name + ", age=" + age + "]";
-
}
-
-
}
-
public class Test3{
-
static String singal = File.separator;
-
public static final File FILE = new File(
-
"C:"+singal+"Users"+singal+"lenovo"+singal+"Desktop"+singal+"Test2.txt");
-
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
-
achieveSer(new Student("lemon",10));
-
opsiteSer();
-
}
-
//实现序列化操作
-
public static void achieveSer(Object object) throws FileNotFoundException, IOException {
-
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(FILE));
-
objectOutputStream.writeObject(object);
-
objectOutputStream.close();
-
}
-
//反序列化操作
-
public static void opsiteSer() throws FileNotFoundException, IOException, ClassNotFoundException {
-
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(FILE));
-
System.out.println(objectInputStream.readObject());
-
objectInputStream.close();
-
}
-
}
对age属性使用transient关键字后的序列化结果:
对age属性使用transient关键字后的序列化结果:
JavaIO——System对IO的支持、序列化的更多相关文章
- java的IO操作:System类对IO的支持。
目标: 1,掌握SYStem对IO的三种支持: system.out system.in system.err 2,掌握system.out及system.err的区别. 3,掌握输入,输出重定向. ...
- java ->IO流_序列化流与反序列化流
序列化流与反序列化流 用于从流中读取对象的操作流 ObjectInputStream 称为 反序列化流 用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流(对象 ...
- Azure Messaging-ServiceBus Messaging消息队列技术系列4-复杂对象消息是否需要支持序列化和消息持久化
在上一篇中,我们介绍了消息的顺序收发保证: Azure Messaging-ServiceBus Messaging消息队列技术系列3-消息顺序保证 在本文中我们主要介绍下复杂对象消息是否需要支持序列 ...
- Java IO(Properties/对象序列化/打印流/commons-io)
Java IO(Properties/对象序列化/打印流/commons-io) Properties Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载. ...
- IO流的序列化和反序列化
序列化和反序列化的概念: 序列化:把对象转换为字节序列的过程称为对象的序列化.(常见的就是存文件) 反序列化:把字节序列恢复为对象的过程称为对象阿德反序列化. 序列化和反序列化的使用: java.io ...
- Newtonsoft.Json高级用法,json序列号,model反序列化,支持序列化和反序列化DataTable,DataSet,Entity Framework和Entity,字符串
原文地址:https://www.cnblogs.com/yanweidie/p/4605212.html 手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口 ...
- 一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型;
导航目录: Newtonsoft.Json 概述 一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型: 二:C#对象.集合.DataTable与Json内容互转示例: ...
- 通过System.CommandLine快速生成支持命令行的应用
一直以来,当我们想让我们的控制台程序支持命令行启动时,往往需要编写大量代码来实现这一看起来很简单的功能.虽然有一些库可以简化一些操作,但整个过程仍然是一个相当枯燥而乏味的过程.我之前也写过一些文章简单 ...
- hive-相关报错处理${system:java.io.tmpdir}
在使用hive的时候启动成功 [root@localhost bin]# ./hive which: no hbase in (/usr/local/hive/apache-hive-2.1.1-bi ...
随机推荐
- 🔥完美解决ESlint+Prettier各项配置冲突的语法报错问题(新手向)
本文重点: 1.解决修改了Prettier默认配置,项目内格式化无法生效 2.解决Prettier缺少配置,函数名和括号之间,自动添加空格 3.settings.json配置项分享 一个程序员,可能非 ...
- 简单理解函数声明(以signal函数为例)
这两天遇到一些声明比较复杂的函数,比如signal函数,那我们先简单说说signal函数的用法:(参考<c陷阱与缺陷>) [signal:几乎所有c语言程序的实现过程中都要用到signal ...
- elementUI下拉框select组件change事件用法
<el-select-custom clearable collapse-tags v-model="searchForm.cardTypeList" @change=&qu ...
- Spring Cache 带你飞(二)
接着上一篇讲了 Spring Cache 如何被 Spring Aop 代理加载对应的代码,以及何如注入相关界面逻辑. Spring Cache 带你飞(一) 本篇我们围绕两个要点展开: 一个数据是如 ...
- 7.深入TiDB:range 范围计算优化
本文基于 TiDB release-5.1进行分析,需要用到 Go 1.16以后的版本 我的博客地址:https://www.luozhiyun.com/archives/605 这篇文章首先会回顾一 ...
- ES6基础知识(Generator 函数应用)
1.Ajax 是典型的异步操作,通过 Generator 函数部署 Ajax 操作,可以用同步的方式表达 function* main() { var result = yield request(& ...
- Docker部署 Mysql .Net6等容器
Centos8安装Docker 1.更新一下yum [root@VM-24-9-centos ~]# yum -y update 2.安装containerd.io # centos8默认使用podm ...
- 美团饿了么领取外卖优惠券微信小程序的开发及上线_怎样点外卖省钱_外卖小程序的开发及上线
都1202年了,估计没人不知道外卖了,那么就有两种人在思考两种问题: 普通人:怎么点外卖划算? 程序员:怎么通过外卖赚钱? 话不多说,为了让你们相信我有能力来讲这块内容,先给你们看一个很简单的小程序: ...
- [loj3503]滚榜
一个小问题:题意中关于$b_{i}$的顺序只需要单调不降即可,相同时可任意选择 考虑$i$优于$j$的条件,即$val_{i}\ge val_{j}+[i>j]$,并记$del_{i,j}=\m ...
- [loj3156]回家路线
令$dp[i]$表示经过第$i$条边后的最小烦躁值,有$且dp[i]=\min_{y_{j}=x_{i}且q_{j}\le p_{i}}dp[j]+f(p_{i}-q_{j})$,其中$f(x)=Ax ...