Day22_IO第四天

时间:2021-11-11 17:07:47

1、合并流(序列流)-SequenceInputStream(了解)

概念
    合并流也叫序列流,可以把多个字节输入流整合成一个, 从序列流中读取数据时, 将从被整合的第一个流开始读, 读完一个之后继续读第二个, 以此类推.

1、将两个输入流合并
  1. public static void demo1() throws FileNotFoundException, IOException {
  2. FileInputStream fis1 = new FileInputStream("a.txt"); //创建字节输入流关联a.txt
  3. FileOutputStream fos = new FileOutputStream("c.txt"); //创建字节输出流关联c.txt
  4. int b1;
  5. while((b1 = fis1.read()) != -1) { //不断的在a.txt上读取字节
  6. fos.write(b1); //将读到的字节写到c.txt上
  7. }
  8. fis1.close(); //关闭字节输入流
  9. FileInputStream fis2 = new FileInputStream("b.txt");
  10. int b2;
  11. while((b2 = fis2.read()) != -1) {
  12. fos.write(b2);
  13. }
  14. fis2.close();
  15. fos.close();
  16. }

2、将多个输入流合并
  1. public static void main(String[] args) throws IOException {
  2. //demo1();
  3. //demo2();
  4. FileInputStream fis1 = new FileInputStream("a.txt");
  5. FileInputStream fis2 = new FileInputStream("b.txt");
  6. FileInputStream fis3 = new FileInputStream("c.txt");
  7. Vector<FileInputStream> v = new Vector<>(); //创建集合对象
  8. v.add(fis1); //将流对象存储进来
  9. v.add(fis2);
  10. v.add(fis3);
  11. Enumeration<FileInputStream> en = v.elements();
  12. SequenceInputStream sis = new SequenceInputStream(en); //将枚举中的输入流整合成一个
  13. FileOutputStream fos = new FileOutputStream("d.txt");
  14. int b;
  15. while((b = sis.read()) != -1) {
  16. fos.write(b);
  17. }
  18. sis.close();
  19. fos.close();
  20. }


2、字节数组流(内存输出流)-ByteArrayOutputStream(掌握)

概念
    该输出流可以向内存中写数据, 把内存当作一个缓冲区, 写出之后可以一次性获取出所有数据
.使用方式
创建对象: new ByteArrayOutputStream()
写出数据: write(int), write(byte[])
获取数据: toByteArray()

案例:定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)


3、随机流-RandomAccessFile(了解)

概述
RandomAccessFile概述
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
支持对文件指定位置的读取和写入。换句话说写入和读取之前必须先指定位置

方法
    read(),write()配合seek(位置)
      1、先调用seek(10)在调用write,在10这个位置写入
      2、先调用seek(10)再调用read,读取10这个位置的数据

4、序列化流(对象操作流)-ObjectInputStream\ObjectOutputStream(掌握)

序列化概念
    把内存中的数据写入到硬盘
反序列化概念
    把硬盘中的数据读取到内存中
注意事项
    被序列化的类要实现Serializable接口


解决黄色警告线问题
    给类增加serialVersionUID属性

方法
    ObjectOutputStream的writeObject() 方法:将对象写入到文件
    ObjectInputStream的readObject()方法:将文件中的对象读取出来

演示:
  1. * 将对象存储在集合中写出
  2. Person p1 = new Person("张三", 23);
  3. Person p2 = new Person("李四", 24);
  4. Person p3 = new Person("马哥", 18);
  5. Person p4 = new Person("辉哥", 20);
  6. ArrayList<Person> list = new ArrayList<>();
  7. list.add(p1);
  8. list.add(p2);
  9. list.add(p3);
  10. list.add(p4);
  11. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f.txt"));
  12. oos.writeObject(list); //写出集合对象
  13. oos.close();








  1. * 读取到的是一个集合对象
  2. ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f.txt"));
  3. ArrayList<Person> list = (ArrayList<Person>)ois.readObject(); //泛型在运行期会被擦除,索引运行期相当于没有泛型
  4. //想去掉黄色可以加注解
  5. @SuppressWarnings("unchecked")
  6. for (Person person : list) {
  7. System.out.println(person);
  8. }
  9. ois.close();


5、数据输入输出流DataInputStream\ DataOutputStream(了解)

1.什么是数据输入输出流
* DataInputStream, DataOutputStream可以按照基本数据类型大小读写数据
* 例如按Long大小写出一个数字, 写出时该数据占8字节. 读取的时候也可以按照Long类型读取, 一次读取8个字节.
2.使用方式
* DataOutputStream(OutputStream), writeInt(), writeLong() 

DataOutputStream dos = new DataOutputStream(new FileOutputStream("b.txt"));
dos.writeInt(997);
dos.writeInt(998);
dos.writeInt(999);
dos.close();
* DataInputStream(InputStream), readInt(), readLong()

DataInputStream dis = new DataInputStream(new FileInputStream("b.txt"));
int x = dis.readInt();
int y = dis.readInt();
int z = dis.readInt();
System.out.println(x);
System.out.println(y);
System.out.println(z);
dis.close();


6、打印流(掌握PrintWriter)

概念
    该流可以很方便的将对象的toString()结果输出, 并且自动加上换行, 而且可以使用自动刷出的模式

特点(掌握)
     A、可以写入任意类型数据
     B、可以自动刷新。必须先启动,并且是使用println.方法才有效,而我们的print方法仅仅是可以写入任意类型的数据
     C、可以直接对文件进行写入
     D、底层调用的是转换流

注意事项(掌握)
     打印流只能输出数据,不能读取数据换句话说就是只能操作数据目的能操作数据源

PrintWriter 和 PrintStream的区别
     1、PrintWriter构造方法可以传入字符流或者字节流,而PrintStream只能传入字节流
     2、PrintWriter想要实现自动刷新构造方法必须手动指定,而PrintStream则不需要手动指定


使用
     我们使用打印流就是为了使用自动刷新功能,所以以下只针对如何实现自动刷新进行案例演示
     
A、PrintWriter的使用方式(掌握)
          1、通过构造方法创建对象并且启用自动刷新功能
                    PrintWriter(OutputStrem out, boolean autoFlush);
                    PrintWriter(Writer out, boolean autoFlush);
          2、调用println\printf\format方法,只有调用这三个个方法才会自动调用flush方法
                
  1. PrintWriter printWriter = newPrintWriter(new FileWriter("d.txt"),true);
  2. printWriter.printf("1");//仅仅写入数据并且刷新
  3. printWriter.println("2");//写入数据并且增加换行符,刷新
  4. printWriter.format("你好 %s", "张三");
B、PrintStream的使用方式
          1、通过构造方法创建对象并且启用自动刷新功能
                              PrintStream(OutputStrem out, boolean autoFlush);
          2、调用println\printf\format方法
  1. PrintStream ps = newPrintStream(new FileOutputStream("a.txt"),true);//,true可有可无
  2. ps.printf("你好");

7、Properties(掌握)

1、概述
     Properties是一个键值对的集合类,不是IO类,键和值都是字符串。可以从流中加载数据或者把数据保存到流中,是唯一一个可以和IO流集合使用的集合类
添加修改
public Object put(Object key, Object value)
添加修改
public Object setProperty(String key,String value)
调用的就是 put方法
获取功能
public String get(String key)
获取
Public String getProperty(String key)
底层调用的是 get
Public String getProperty(String, String defaultValue)
底层调用 get,如果找不到,返回 defaultValue
public Set<String> stringPropertyNames()
获取键集合
转换功能
public void list(PrintWriter out)
将当前的集合里面的键值保存到指定的文本中
 
public void list(PrintStream out)
public void load(InputStream inputStream)
从输入流中读取属性和列表
public void load(Reader reader)
public void store(OutputStream out, String comment)
把集合中的数据保存到文本中
public void store(Writer writer, String comments)
public Set keySet()
获取所有键的集合

注意:Properties类在以后Android中会有新的Properties替代,在EE中我们会重新封装一个Properties工具类,因为Properties的缺点很明显,不能直接操作File对象

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
public class PropertiesDemo {
    /**
     * 通过Properties修改config.inf中的PhoneIndex,值修改成123
     * @param args
     */
    public static void main(String[] args) throws Exception {
        /*
         * 1、加载config.inf
         * 2、在内存修改config.inf中的phoneIndex
         * 3、将修改后的集合重新写入到配置文件
         */
        Properties p  = new Properties();
        p.load(new FileInputStream("config.inf"));
        
        
        p.put("PhoneIndex","123");
        p.store(new FileOutputStream("config.inf"), "PhoneIndex被修改过!!!");
        
    }
}
  

8、System类(掌握)

1、系统类,提供了静态的变量和方法供我们使用
2、成员方法

public static void exit(int value)

退出jvm,非0表示异常退出

public static long currentTimeMillis()

返回当前系统时间的毫秒值

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

从指定源数的指定位置开始复制,赋值到目标数组的指定位置

public static Properties getProperties();

获取当前系统的属性

public static String getProperty(String key)

获取指定键描述的系统属性

public static String getProperty(String key, String defaultValue)

获取指定键描述的系统属性,没有找到该键的话返回defaultValue


遍历Properties 

  1. /**
  2. * 遍历系统描述Properties
  3. */
  4. public static voidmain(String[] args) throws Exception{
  5. Properties properties = System.getProperties();
  6. Set<Object> keySet = properties.keySet();
  7. for(Object key:keySet){
  8. System.out.println(key +"*****"+properties.get(key));
  9. }
  10. }

获取当前系统中的换行符
  1. /**
  2. * 获取当前系统中的换行符
  3. */
  4. public static voidmain(String[] args) throws Exception{
  5. String line = System.getProperty("line.separator");
  6. System.out.println(line+"你好");
  7. }


9、IO体系(掌握)

Day22_IO第四天



10、案例(掌握)

1、定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)
2、两种方式实现键盘录入
3、改变标准输入输出流拷贝图片
4、我有一个学生类,这个类包含以下成员变量:姓名,语文成绩,数学成绩,英语成绩。

请从键盘录入5个学生信息,然后按照自己定义的格式存储到文本文件中。

要求被存储的学生按照分数从高到低排序

5、定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(两种方式,不用字节数组流做)

11、案例代码(掌握)

1、定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)
  1. package com.heima.test;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6. public class Test1 {
  7. /**
  8. * @param args
  9. * 定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)
  10. *
  11. * 分析:
  12. * 1,reda(byte[] b)是字节输入流的方法,创建FileInputStream,关联a.txt
  13. * 2,创建内存输出流,将读到的数据写到内存输出流中
  14. * 3,创建字节数组,长度为5
  15. * 4,将内存输出流的数据全部转换为字符串打印
  16. * 5,关闭输入流
  17. * @throws IOException
  18. */
  19. public static void main(String[] args) throws IOException {
  20. //1,reda(byte[] b)是字节输入流的方法,创建FileInputStream,关联a.txt
  21. FileInputStream fis = new FileInputStream("a.txt");
  22. //2,创建内存输出流,将读到的数据写到内存输出流中
  23. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  24. //3,创建字节数组,长度为5
  25. byte[] arr = new byte[5];
  26. int len;
  27. while((len = fis.read(arr)) != -1) {
  28. baos.write(arr, 0, len);
  29. //System.out.println(new String(arr,0,len));
  30. }
  31. //4,将内存输出流的数据全部转换为字符串打印
  32. System.out.println(baos); //即使没有调用,底层也会默认帮我们调用toString()方法
  33. //5,关闭输入流
  34. fis.close();
  35. }
  36. }

2、两种方式实现键盘录入
  1. package com.heima.otherio;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.util.Scanner;
  6. public class Demo07_SystemIn {
  7. /**
  8. * @param args
  9. * @throws IOException
  10. */
  11. public static void main(String[] args) throws IOException {
  12. //方式1
  13. /*BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //InputStreamReader转换流
  14. String line = br.readLine();
  15. System.out.println(line);
  16. br.close();*/
  17. //方式2
  18. Scanner sc = new Scanner(System.in);
  19. String line = sc.nextLine();
  20. System.out.println(line);
  21. sc.close();
  22. }
  23. }

3、改变标准输入输出流拷贝图片
  1. package com.heima.test;
  2. import java.io.FileInputStream;
  3. import java.io.FileNotFoundException;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.PrintStream;
  7. public class Test2 {
  8. /**
  9. * @param args
  10. * @throws IOException
  11. */
  12. public static void main(String[] args) throws IOException {
  13. System.setIn(new FileInputStream("双元.jpg")); //改变标准输入流
  14. System.setOut(new PrintStream("copy.jpg")); //改变标准输出流
  15. InputStream is = System.in;
  16. PrintStream ps = System.out;
  17. byte[] arr = new byte[1024];
  18. int len;
  19. while((len = is.read(arr)) != -1) {
  20. ps.write(arr, 0, len);
  21. }
  22. is.close();
  23. ps.close();
  24. }
  25. }
4、我有一个学生类,这个类包含以下成员变量:姓名,语文成绩,数学成绩,英语成绩。

请从键盘录入5个学生信息,然后按照自己定义的格式存储到文本文件中。

要求被存储的学生按照分数从高到低排序


  1. package cn.itcast;
  2. import java.io.BufferedWriter;
  3. import java.io.FileWriter;
  4. import java.io.IOException;
  5. import java.util.Comparator;
  6. import java.util.Scanner;
  7. import java.util.TreeSet;
  8. /*
  9. * 我有一个学生类,这个类包含一下成员变量:姓名,语文成绩,数学成绩,英语成绩。
  10. * 请从键盘录入5个学生信息,然后按照自己定义的格式存储到文本文件中。
  11. * 要求被存储的学生按照分数从高到低排序。
  12. *
  13. * 分析:
  14. * A:写一个学生类,有4个成员变量。
  15. * B:用Scanner实现键盘录入。
  16. * C:把这多个学生进行存储。用集合。
  17. * 那么,用哪个集合呢?
  18. * 由于最终需要排序,所以,我们选择TreeSet集合。
  19. * D:遍历集合,获取到集合中的每一个数据,用输出流写到文本文件。
  20. * name chinese math english
  21. */
  22. public class StudentTest {
  23. public static void main(String[] args) throws IOException {
  24. // 写一个学生类,有4个成员变量。
  25. System.out.println("学生信息录入开始");
  26. // 定义TreeSet集合
  27. TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
  28. @Override
  29. public int compare(Student s1, Student s2) {
  30. // 主要条件
  31. int num = s2.getSum() - s1.getSum();
  32. // 分析次要条件
  33. // 当总分相同,还得继续比较每一门的分数是否相同
  34. int num2 = (num == 0) ? s1.getChinese() - s2.getChinese() : num;
  35. int num3 = (num2 == 0) ? s1.getMath() - s2.getMath() : num2;
  36. // 当语文,数学,英语成绩都相同的,我们还得继续判断姓名是否相同。
  37. int num4 = (num3 == 0) ? s1.getName().compareTo(s2.getName())
  38. : num3;
  39. return num4;
  40. }
  41. });
  42. for (int x = 0; x < 5; x++) {
  43. // 用Scanner实现键盘录入。
  44. Scanner sc = new Scanner(System.in);
  45. // 键盘录入数据
  46. System.out.println("请输入第" + (x + 1) + "个学生的姓名:");
  47. String name = sc.nextLine();
  48. System.out.println("请输入第" + (x + 1) + "个学生的语文成绩:");
  49. int chinese = sc.nextInt();
  50. System.out.println("请输入第" + (x + 1) + "个学生的数学成绩:");
  51. int math = sc.nextInt();
  52. System.out.println("请输入第" + (x + 1) + "个学生的英语成绩:");
  53. int english = sc.nextInt();
  54. // 把数据封装到学生对象中
  55. Student s = new Student();
  56. s.setName(name);
  57. s.setChinese(chinese);
  58. s.setMath(math);
  59. s.setEnglish(english);
  60. ts.add(s);
  61. }
  62. // 遍历集合,获取到集合中的每一个数据,用输出流写到文本文件。
  63. BufferedWriter bw = new BufferedWriter(new FileWriter("students.txt"));
  64. bw.write("姓名\t语文\t数学\t英语");
  65. bw.newLine();
  66. bw.flush();
  67. for (Student s : ts) {
  68. StringBuilder sb = new StringBuilder();
  69. sb.append(s.getName()).append("\t").append(s.getChinese())
  70. .append("\t").append(s.getMath()).append("\t")
  71. .append(s.getEnglish());
  72. bw.write(sb.toString());
  73. bw.newLine();
  74. bw.flush();
  75. }
  76. bw.close();
  77. System.out.println("学生信息录入成功");
  78. }
  79. }

  1. package cn.itcast;
  2. public class Student {
  3. private String name;
  4. private int chinese;
  5. private int math;
  6. private int english;
  7. public Student() {
  8. }
  9. public Student(String name, int chinese, int math, int english) {
  10. super();
  11. this.name = name;
  12. this.chinese = chinese;
  13. this.math = math;
  14. this.english = english;
  15. }
  16. public String getName() {
  17. return name;
  18. }
  19. public void setName(String name) {
  20. this.name = name;
  21. }
  22. public int getChinese() {
  23. return chinese;
  24. }
  25. public void setChinese(int chinese) {
  26. this.chinese = chinese;
  27. }
  28. public int getMath() {
  29. return math;
  30. }
  31. public void setMath(int math) {
  32. this.math = math;
  33. }
  34. public int getEnglish() {
  35. return english;
  36. }
  37. public void setEnglish(int english) {
  38. this.english = english;
  39. }
  40. public int getSum() {
  41. return this.chinese + this.math + this.english;
  42. }
  43. }


5、定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(两种方式,不用字节数组流做)
  1. FileInputStream fileInputStream = new FileInputStream("LineNumberReader.java");
  2. byte[] data = new byte[fileInputStream.available()];
  3. int len = fileInputStream.read(data);
  4. System.out.println(new String(data,0,len));

12、关于Serializable的Serial Version ID的讨论(了解)

    我们编写一个实现了Serializable接口(序列化标志接口)的类,Eclipse马上就会给一个黄色警告:需要增加一个Serial Version ID。为什么要增加它是怎么计算出来的?有什么用?


    1、为什么要增加?
            类实现Serializable接口的目的是为了将内存中的对象保存到本地磁盘或者通过网络传输(也就是可持久化)
Day22_IO第四天
  1. package io;
  2. /**
  3. * 腾讯新闻手机客户端
  4. * @author haoyongliang
  5. *
  6. */
  7. public class Consumer {
  8. public static void main(String[] args) {
  9. Person person = (Person)SerializationUtils.readObject();
  10. System.out.println(person.getName());
  11. }
  12. }


  1. package io;
  2. /**
  3. * 腾讯新闻服务器
  4. * @author haoyongliang
  5. *
  6. */
  7. public class Producer {
  8. public static void main(String[] args) {
  9. Person person = new Person();
  10. person.setName("混世魔王");
  11. SerializationUtils.writeObject(person);
  12. }
  13. }

  1. package io;
  2. import java.io.FileInputStream;
  3. import java.io.FileOutputStream;
  4. import java.io.ObjectInputStream;
  5. import java.io.ObjectOutputStream;
  6. import java.io.Serializable;
  7. /**
  8. * 序列化工具类
  9. * @author haoyongliang
  10. *
  11. */
  12. public class SerializationUtils {
  13. /** 序列化后的对象存储路径 */
  14. private static final String FILE_NAME = "C://obj.bin";
  15. public static void writeObject(Serializable s) {
  16. try (
  17. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_NAME));
  18. ){
  19. oos.writeObject(s);//将对象写入到C://obj.bin
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. public static Object readObject(){
  25. Object obj = null;
  26. try(
  27. ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_NAME))
  28. ){
  29. obj = ois.readObject();
  30. }catch(Exception e){
  31. e.printStackTrace();
  32. }
  33. return obj;
  34. }
  35. }

13、今天必须掌握的内容,面试题,笔试题。(掌握这个就可以放心学习后面的知识了)

1、说说合并流是干什么的
2、说说字节数组流是干什么的,底层是什么
3、说说随即流可以干什么
4、说说序列化流,并且通过序列化流将学生对象写入文件,并且将文件中的数据读取成学生对象
5、打印流有哪些,打印流可以读取数据吗?打印流的特点是什么,要想启用刷新功能,必须调用哪个方法
6、代码题:定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)
7、代码题:两种方式实现键盘录入
8、代码题:我有一个学生类,这个类包含以下成员变量:姓名,语文成绩,数学成绩,英语成绩。

请从键盘录入5个学生信息,然后按照自己定义的格式存储到文本文件中。

要求被存储的学生按照分数从高到低排序

9、Properties的load store方法掌握