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. Vue 基础自查——watch、computed和methods的区别

    1 前言 创建一个Vue实例时,可以传入一个选项对象 const vm = new Vue({ data: { msg: 'hello' }, computed: {}, methods: {}, w ...

  2. LeetCode88 合并有序数组

    1. 这道题为简单题目,但是还有需要好好思考的 2. 首先不能使用额外数组合并,不然就没得后文了 3. nums1后面有0填充,且填充数量正好是n,整个数组大小即m+n能够容纳合并后的数据 4.既然要 ...

  3. Xshell Error Report,Program has stopped working

    xftp和xshell突然都无法运行并报错如图 图中的意思是,xshell有错误,官方想收集错误.可是也不能给你发送了,还这样啊. 解决办法 1.卸载Xshell和Xftp,重新安装. 参考:http ...

  4. 大爽Python入门教程 2-4 练习

    大爽Python入门公开课教案 点击查看教程总目录 方位输出 第一章有一个思考题,方位变换: 小明同学站在平原上,面朝北方,向左转51次之后(每次只转90度), 小明面朝哪里?小明转过了多少圈? (3 ...

  5. 基于Netty4手把手实现一个带注册中心和注解的Dubbo框架

    阅读这篇文章之前,建议先阅读和这篇文章关联的内容. 1. 详细剖析分布式微服务架构下网络通信的底层实现原理(图解) 2. (年薪60W的技巧)工作了5年,你真的理解Netty以及为什么要用吗?(深度干 ...

  6. [ARC117E]Zero-Sum Ranges 2

    令$sum_{i}=\sum_{j=1}^{i}a_{j}$,即要求其满足: 1.$sum_{0}=sum_{2n}=0$且$\forall 1\le i\le 2n,|sum_{i}-sum_{i- ...

  7. 【贾志豪NOIP模拟题】慰问员工 cheer 【最小生成树】【对边权值的一些处理】

    Description LongDD 变得非常懒, 他不想再继续维护供员工之间供通行的道路. 道路被用来连接 N(5 <= N <= 10,000)个房子, 房子被连续地编号为 1..N. ...

  8. Codeforces 306D - Polygon(随机化+乱搞)

    Codeforces 题目传送门 & 洛谷题目传送门 中考终于结束了--简单写道题恢复下状态罢. 首先这一类题目肯定没法用一般的方法解决,因此考虑用一些奇淫的乱搞做法解决这道题,不难发现,如果 ...

  9. 一类利用队列优化的DP

    I.导入: 这是一个\(O(n^2)\)的状态和转移方程: \[f(i,j)=\left\{ \begin{aligned} f(i-1,j-1)+k \ (1\leq j)\\ \max_{k \i ...

  10. 『学了就忘』Linux文件系统管理 — 61、使用parted命令进行分区

    目录 1.parted命令介绍 2.parted交互模式 3.建立分区 (1)查看分区 (2)修改成GPT分区表 (3)建立分区 (4)建立文件系统(格式化) (5)调整分区大小 (6)删除分区 1. ...