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. 计算机网络-3-2-点对点协议PPP

    点对点协议PPP 在通信链路较差的年代,在数据链路层使用可靠传输协议曾经是一种好方法,比较简单的点对点PPP协议则是目前使用最广泛的数据链路层协议. PPP协议的特点 互联网用户通过都要连接到某个IS ...

  2. C++ 指针的引用和指向引用的指针

    指向引用的指针 简单使用指针的一个例子就是: int a = 1; int *p = &a; 预先强调: 没有指向引用的指针 原因: 因为引用 不是对象,没有地址. 但是指向引用的指针是什么形 ...

  3. this.$set用法

    this.$set()的主要功能是解决改变数据时未驱动视图的改变的问题,也就是实际数据被改变了,但我们看到的页面并没有变化,这里主要讲this.$set()的用法,如果你遇到类似问题可以尝试下,vue ...

  4. 端口被占用(启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099的解决办法)

    一.问题描述 在IntelliJ IDEA 中启动Tomcat服务器时就出现了如下图所示的错误: 错误: 代理抛出异常错误**: java.rmi.server.ExportException: Po ...

  5. SpringBoot中使用@ConfigurationProperties提示:Configuration Annotation Processor not found in classpath

    问题 Springboot1.5以上版本,在使用 @ConfigurationProperties注解的时候会提示Spring Boot Configuration Annotation Proces ...

  6. PTA 7-2 哈夫曼编码 (30分)

    PTA 7-2 哈夫曼编码 (30分) 给定一段文字,如果我们统计出字母出现的频率,是可以根据哈夫曼算法给出一套编码,使得用此编码压缩原文可以得到最短的编码总长.然而哈夫曼编码并不是唯一的.例如对字符 ...

  7. java 模版式的 word

    ... package com.kingzheng.projects.word; import java.io.BufferedWriter; import java.io.File; import ...

  8. sui Mobile 试玩

    .... 突然就用上这东西还不熟悉就写了一个页面而已 <a class="open-popup button pull-right create-actions" id=&q ...

  9. [51nod1237]最大公约数之和V3

    $\sum_{i=1}^{n}\sum_{j=1}^{n}gcd(i,j)\\$ $=\sum_{d=1}^{n}d\sum_{i=1}^{n/d}\sum_{j=1}^{n/d}\varepsilo ...

  10. [cf1168E]Xor Permutations

    (与题目中下标不同,这里令下标为$[0,2^{k})$来方便运算) 根据异或的性质,显然有解的必要条件是$\bigoplus_{i=0}^{2^{k}-1}a_{i}=0$ 在此基础上,我们考虑构造- ...