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输出的位置将变为屏幕。


  1. /*
  2. * 系统输出
  3. * */
  4. public class Test3{
  5. public static void main(String[] args) throws IOException {
  6. OutputStream outputStream = System.out;
  7. outputStream.write("你好!".getBytes());
  8. }
  9. }

(2)系统输入

与前面两者不同的是System.in是InputStream的对象。而这种输入操作是指用户通过键盘输入(用户输入)。Java本身并没有直接的用户输入,所以要想实现这样的操作,还得借助java.io模式来完成。


  1. /*
  2. * 系统输入
  3. * */
  4. public class Test3{
  5. public static void main(String[] args) throws IOException {
  6. InputStream inputStream = System.in;
  7. byte[] data = new byte[1024];
  8. System.out.println("请输入:");
  9. //将数据读取到字节数组中
  10. int temp = inputStream.read(data);
  11. System.out.println("输出为:"+new String(data,0,temp));
  12. inputStream.close();
  13. }
  14. }

通过程序我们可以发现:当用户输入信息时程序需要暂停执行,这是因为程序进入了阻塞状态,直至我们输入操作完成后按回车,程序才可以继续向下进行。且以上程序中我们是采用开辟固定长度的字节数组,当我们输入的字节大于该固定长度时就会出现读取部分数据的结果。这是因为一次读取不完造成的结果。所以我们将引入内存流对其进行改进,先将这些数据保存在内存流中然后一次性进行取出。


  1. /*
  2. * 输入字节数大于开辟数组的大小
  3. * */
  4. public class Test3{
  5. public static void main(String[] args) throws IOException {
  6. InputStream inputStream = System.in;
  7. byte[] data = new byte[16];
  8. System.out.println("请输入:");
  9. //将数据读取到字节数组中
  10. int temp = inputStream.read(data);
  11. System.out.println("输出为:"+new String(data,0,temp));
  12. inputStream.close();
  13. }
  14. }


  1. /*
  2. * 内存流进行改进操作
  3. * */
  4. public class Test3{
  5. public static void main(String[] args) throws IOException {
  6. InputStream inputStream = System.in;
  7. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  8. byte[] data = new byte[16];
  9. System.out.println("请输入:");
  10. int temp = 0;
  11. while((inputStream.read(data)) != -1) {
  12. //保存数据到内存输出流中
  13. byteArrayOutputStream.write(data,0,temp);
  14. //用户判断输入结束
  15. if(temp < data.length) {
  16. break;
  17. }
  18. break;
  19. }
  20. inputStream.close();
  21. byteArrayOutputStream.close();
  22. System.out.println("输出为:"+new String(byteArrayOutputStream.toByteArray()));
  23. }
  24. }

由此我们可以发现虽然实现了用键盘输入数据的功能,但是使得整体的实现逻辑过于混乱,所以说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类。


  1. /*
  2. * 利用BufferedReader类实现键盘输入
  3. * */
  4. public class Test3{
  5. public static void main(String[] args) throws IOException {
  6. BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
  7. System.out.println("请输入:");
  8. //默认使用回车换行,默认的换行模式也是BufferReader的缺点
  9. String string = bufferedReader.readLine();
  10. System.out.println("输出为:"+string);
  11. }
  12. }

使用以上形式实现的键盘输入还有一个大特点,由于接收的数据类型为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)


  1. /*
  2. * 使用Scanner类实现数据输入
  3. * */
  4. public class Test3{
  5. public static void main(String[] args) {
  6. Scanner scanner = new Scanner(System.in);
  7. System.out.println("请输入:");
  8. //有输入内容不判断空字符串
  9. if(scanner.hasNext()) {
  10. //遇到空格、制表符、回车均停止数据的读取
  11. // System.out.println("输入内容为:"+scanner.next());
  12. //只有遇到回车才停止数据的读取
  13. System.out.println("输入内容为:"+scanner.nextLine());
  14. }
  15. scanner.close();
  16. }
  17. }

             

通过上述运行结果我们可以验证nextXXX()方法进行相应数据类型数据的读取时,只要遇到空格就停止读取数据。

最为重要的是,Scanner可以对接收的数据类型使用正则表达式判断。


  1. /*
  2. * 自定义格式输出
  3. * */
  4. public class Test3{
  5. public static void main(String[] args) {
  6. Scanner scanner = new Scanner(System.in);
  7. System.out.println("请输入出生日期:");
  8. if(scanner.hasNext("\\d{4}-\\d{2}-\\d{2}")) {
  9. String string = scanner.nextLine();
  10. System.out.println("出生日期为:"+string);
  11. }else {
  12. System.out.println("输入格式错误");
  13. }
  14. }
  15. }

使用Scanner本身能够接收的是一个InputStream对象,那么也就意味着可以接收任意输入流,例如:文件输入流;Scanner完美的替代了BufferedReader,而且更好的实现了InputStream的操作。


  1. /*
  2. * 使用Scanner操作文件
  3. * */
  4. public class Test3{
  5. public static void main(String[] args) throws FileNotFoundException {
  6. String singal = File.separator;
  7. Scanner scanner = new Scanner(new FileInputStream(
  8. new File("C:"+singal+"Users"+singal+"lenovo"+singal+"Desktop"+singal+"Test2.txt")));
  9. //自定义分隔符
  10. scanner.useDelimiter("\n");
  11. while(scanner.hasNext()) {
  12. System.out.println(scanner.next());
  13. }
  14. scanner.close();
  15. }
  16. }

所以以后除了二进制文件拷贝的处理之外,只要是针对程序的信息输出都是用打印流(PrintStream、 PrintWriter),信息输出使用Scanner。

2、序列化

(1)概念

所谓的序列化指的是将程序中的属性以二进制流的形式在网络上传输或者保存在文件中。

可进行序列化的要求:并不意味着所有类的对象都可以被序列化,需要被序列化的类对象往往需要传输使用,同时这个类必须实现 java.io.Serializable接口。这个接口并没有任何的方法定义,只是一个标识而已。

(2)序列化与反序列化的实现

如果要想实现序列化与反序列化的对象操作,在java.io包中提供有两个处理类:ObjectOutputStream、ObjectInputStream


  1. /*
  2. * 实现序列化与反序列化
  3. * */
  4. //定义要被序列化的类
  5. class Student implements Serializable{
  6. private String name = "lemon";
  7. //要使用包装类
  8. private Integer age = 20;
  9. Student(String name, Integer age) {
  10. super();
  11. this.name = name;
  12. this.age = age;
  13. }
  14. //覆写toString方法
  15. public String toString() {
  16. return "Student [name=" + name + ", age=" + age + "]";
  17. }
  18. }
  19. public class Test3{
  20. static String singal = File.separator;
  21. public static final File FILE = new File(
  22. "C:"+singal+"Users"+singal+"lenovo"+singal+"Desktop"+singal+"Test2.txt");
  23. public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
  24. achieveSer(new Student("lemon",10));
  25. opsiteSer();
  26. }
  27. //实现序列化操作
  28. public static void achieveSer(Object object) throws FileNotFoundException, IOException {
  29. ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(FILE));
  30. objectOutputStream.writeObject(object);
  31. objectOutputStream.close();
  32. }
  33. //反序列化操作
  34. public static void opsiteSer() throws FileNotFoundException, IOException, ClassNotFoundException {
  35. ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(FILE));
  36. System.out.println(objectInputStream.readObject());
  37. objectInputStream.close();
  38. }
  39. }

实现序列化:

实现反序列化:

(3)transient关键字

由于Serializable默认会将对象中所有属性进行序列化保存,如果现在某些属性不希望被保存了,那么就可以 使用transient关键字。

修改上述代码(在age属性上加transient关键字)


  1. //定义要被序列化的类
  2. class Student implements Serializable{
  3. private String name = "lemon";
  4. //要使用包装类
  5. private transient Integer age = 20;
  6. Student(String name, Integer age) {
  7. super();
  8. this.name = name;
  9. this.age = age;
  10. }
  11. //覆写toString方法
  12. public String toString() {
  13. return "Student [name=" + name + ", age=" + age + "]";
  14. }
  15. }
  16. public class Test3{
  17. static String singal = File.separator;
  18. public static final File FILE = new File(
  19. "C:"+singal+"Users"+singal+"lenovo"+singal+"Desktop"+singal+"Test2.txt");
  20. public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
  21. achieveSer(new Student("lemon",10));
  22. opsiteSer();
  23. }
  24. //实现序列化操作
  25. public static void achieveSer(Object object) throws FileNotFoundException, IOException {
  26. ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(FILE));
  27. objectOutputStream.writeObject(object);
  28. objectOutputStream.close();
  29. }
  30. //反序列化操作
  31. public static void opsiteSer() throws FileNotFoundException, IOException, ClassNotFoundException {
  32. ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(FILE));
  33. System.out.println(objectInputStream.readObject());
  34. objectInputStream.close();
  35. }
  36. }

对age属性使用transient关键字后的序列化结果:

对age属性使用transient关键字后的序列化结果:

JavaIO——System对IO的支持、序列化的更多相关文章

  1. java的IO操作:System类对IO的支持。

    目标: 1,掌握SYStem对IO的三种支持: system.out system.in system.err 2,掌握system.out及system.err的区别. 3,掌握输入,输出重定向. ...

  2. java ->IO流_序列化流与反序列化流

    序列化流与反序列化流 用于从流中读取对象的操作流 ObjectInputStream    称为 反序列化流 用于向流中写入对象的操作流 ObjectOutputStream   称为 序列化流(对象 ...

  3. Azure Messaging-ServiceBus Messaging消息队列技术系列4-复杂对象消息是否需要支持序列化和消息持久化

    在上一篇中,我们介绍了消息的顺序收发保证: Azure Messaging-ServiceBus Messaging消息队列技术系列3-消息顺序保证 在本文中我们主要介绍下复杂对象消息是否需要支持序列 ...

  4. Java IO(Properties/对象序列化/打印流/commons-io)

    Java IO(Properties/对象序列化/打印流/commons-io) Properties Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载. ...

  5. IO流的序列化和反序列化

    序列化和反序列化的概念: 序列化:把对象转换为字节序列的过程称为对象的序列化.(常见的就是存文件) 反序列化:把字节序列恢复为对象的过程称为对象阿德反序列化. 序列化和反序列化的使用: java.io ...

  6. Newtonsoft.Json高级用法,json序列号,model反序列化,支持序列化和反序列化DataTable,DataSet,Entity Framework和Entity,字符串

    原文地址:https://www.cnblogs.com/yanweidie/p/4605212.html 手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口 ...

  7. 一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型;

    导航目录: Newtonsoft.Json 概述 一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型:    二:C#对象.集合.DataTable与Json内容互转示例: ...

  8. 通过System.CommandLine快速生成支持命令行的应用

    一直以来,当我们想让我们的控制台程序支持命令行启动时,往往需要编写大量代码来实现这一看起来很简单的功能.虽然有一些库可以简化一些操作,但整个过程仍然是一个相当枯燥而乏味的过程.我之前也写过一些文章简单 ...

  9. hive-相关报错处理${system:java.io.tmpdir}

    在使用hive的时候启动成功 [root@localhost bin]# ./hive which: no hbase in (/usr/local/hive/apache-hive-2.1.1-bi ...

随机推荐

  1. sudo 命令详解

    在linux系统中,由于root的权限过大,一般情况都不使用它.只有在一些特殊情况下才采用登录root执行管理任务,一般情况下临时使用root权限多采用su和sudo命令. 一.su和sudo命令对比 ...

  2. ansible模块及语法

    常用模块详解 模块说明及示例: 1.ping模块ping模块 主要用于判断远程客户端是否在线,用于ping本身服务器,返回值是changed.ping示例 ansible clu -m ping 2. ...

  3. Docker 部署前后端项目

    Docker 部署前后端项目 平生不会相思,才会相思,便害相思. 简介:都是被逼的,从零开始一个Docker 部署九个微服务和三个前端项目.其中,这些服务需要用到Nacos.MySQL.Nginx.E ...

  4. 攻防世界 WEB 高手进阶区 XCTF Web_php_unserialize Writeup

    攻防世界 WEB 高手进阶区 XCTF Web_php_unserialize Writeup 题目介绍 题名考点 PHP反序列化漏洞 正则匹配 Writeup <?php class Demo ...

  5. 01 | let 和 const语法 | es6

    01 | let 和 const语法 ES6新增了let命令,用来声明变量.它的用法类似于var,但也有区别 let 和 var 1.作用范围不同 var声明的变量在全局范围内都有效,所以全局只有一个 ...

  6. pyinstaller打包:AttributeError: module ‘win32ctypes.pywin32.win32api’ has no attribute ‘error’

    pyinstaller打包:AttributeError: module 'win32ctypes.pywin32.win32api' has no attribute 'error' 是因为pyin ...

  7. TLFS 内存分配算法详解

    文章目录 1. DSA 背景介绍 1.1 mmheap 1.2 mmblk 2. TLFS 原理 2.1 存储结构 2.2 内存池初始化 2.3 free 2.4 malloc 参考资料 1. DSA ...

  8. 10分钟简单学习net core集成jwt权限认证,快速接入项目落地使用

    什么是JWT JSON Web Token(JWT)是目前最流行的跨域身份验证.分布式登录.单点登录等解决方案. JWT的官网地址:https://jwt.io/ 通俗地来讲,JWT是能代表用户身份的 ...

  9. Centos8 Docker部署 .Net6 项目

    .Net6项目发布 1.在VS中发布项目,并编写好Dockerfile文件 Dockerfile文件内容如下: FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS ...

  10. JDBC操作多张表一

    一.操作一对多情况开发步骤1创建对象 //代码部门的对象public class Department { private String id; private String name; privat ...