• 019.day19 缓冲流 对象流 标准输入输出流


    缓冲流和对象流

    本节任务

    缓冲流

    对象流

    标准输入输出流

    教学目标

    掌握缓冲流的用法

    掌握序列化和反序列化

    掌握标准输入输出流的用法

    教学内容

    一、缓冲流

    主要为了提高读写效率,增强基础流的功能

    • 实例化File对象
    • 实例化缓冲流对象,需要基础流作为参数

    1. 缓冲输入流

    (1)BufferedInputStream
    // TODO 字符缓冲输入流BufferedReader
    		// 1.实例化一个BufferedReader
    		// 默认缓冲区大小:8192,当标记中指定的记录的字符数小于缓冲数组剩余长度时,不会发生异常
    		// 当缓冲数组足够大时,该标记一直会保留到当前缓冲数组装满
    		Reader reader = new BufferedReader(new FileReader(new File("f:/test.txt")),5);
    		// 2.BufferedReader中支持mark和reset
    		String result = "";
    		// 3.使用mark进行标记
    		result += (char)reader.read();
    		result += (char)reader.read();
    		result += (char)reader.read();
    		result += (char)reader.read();
    		// mark当中参数的作用:再读取多少个字符之后,标记点失效
    		reader.mark(3);
    		// 4.使用reset方法返回标记的位置
    		result += (char)reader.read();
    		result += (char)reader.read();
    		result += (char)reader.read();
    		// 失效:limit -> 要求记录的字符数 -> 失效条件:读取的字符总数会超出缓冲区大小
    		// 当需要记录的字符刚好超出了当前缓冲区,会在下一个缓冲区中继续存放,直到下一个缓冲区存满,标记失效
    		reader.reset();
    		result += (char)reader.read();
    		result += (char)reader.read();
    		result += (char)reader.read();
    		System.out.println(result);
    		reader.close();
    
    • mark(int marklimit):标记位置
    • reset():如果可能,回到标记位置
    // TODO 缓冲流-标记和重置练习
    		// 在文本文件中指定一对特殊字符(能够被唯一识别的)
    		// 当读取到第一个特殊字符时,标记当前位置
    		// 当读取到第二个特殊字符时,重置,继续读取完所有文件内容
    		Reader reader = new BufferedReader(new FileReader(new File("f:/test.txt")));
    		int i = 0;
    		int count = 1;
    		String result = "";
    		while ((i = reader.read()) != -1) {
    			if ('!' == (char)i && count == 1) {
    				reader.mark(30);
    				count ++;
    			}else if('!' == (char)i && count == 2) {
    				reader.reset();
    				count ++;
    			}
    			result += (char)i;
    		}
    		System.out.println(result);
    		reader.close();
    
    (2)BufferedReader
    • readLine():直接读取一行
    // TODO 字符缓冲流 - 每次读取一行 - 读取文件中所有内容
    		// 1.初始化缓冲流
    		BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("E:/test.txt")));
    		String line = "";
    		// 2.读取文件内容
    		while ((line = bufferedReader.readLine()) != null) {
    			// 读取的内容本身不包括换行符
    			System.out.println(line);
    		}
    		// 3.关闭流
    		bufferedReader.close();
    
    • 小练习

      // TODO 从文件中读取所有数据 - 单词计数
      		// 1.数据采集 - 数据来源:文本文件
      		// (1)指定文件路径
      		// 使用File类指定数据文件路径
      		File dataFile = new File("E:/data.txt");
      		// 使用dataFile初始化一个输入流
      		Reader fileReader = new FileReader(dataFile);
      		// 使用fileReader初始化一个缓冲流
      		BufferedReader bufferedReader = new BufferedReader(fileReader);
      		// (2)使用缓冲流一次读取一行
      		// 定义一个集合,存储读取到的数据
      		List<String> lines = new ArrayList<>();
      		// 定义字符串变量,接收每次读取的一行数据
      		String temp = "";
      		// (3)将获取到的数据存放到集合当中
      		while ((temp = bufferedReader.readLine()) != null) {
      			lines.add(temp);
      		}
      		// (4)关闭流 -> 关闭顺序与打开顺序相反
      		bufferedReader.close();
      		fileReader.close();
      		// 2.数据清洗 - 去除重复、缺失、偏差较大的数据
      		// 3.数据分析 - 统计计数
      		Map<String, Integer> result = new HashMap<>();
      		// (1)从集合中获取到每一行数据
      		for (String line : lines) {
      			// (2)根据相应的分隔符取出每一个单词作为待统计数据
      			String[] words = line.split(" ");
      			for (String word : words) {
      				// (3)当某一个单词第一次出现时,记为1
      				// (4)当某一个单词再次出现时,将出现的次数累加
      				// 第一次出现该单词
      				if (!result.containsKey(word)) {
      					result.put(word, 1);
      				}else {
      					// 取出当前单词已经出现的次数
      					int count = result.get(word);
      					result.put(word, count + 1);
      				}
      			}
      		}
      		// (5)重复以上步骤,直到遍历结束
      		// 4.结果打印
      		for (Map.Entry<String, Integer> string : result.entrySet()) {
      			System.out.println(string);
      		}
      

    2. 缓冲输出流

    (1)BufferedOutputStream
    (2)BufferedWriter
    • newLine():写入一个行分隔符

    二、对象流

    如果流中流动的数据是对象则可称为对象流

    • 序列化:将一个对象写入到本地文件中
    • 反序列化:将一个本地文本文件中的对象读取出来
    • 一个对象流只能操作一个对象
    • 当需要同时序列化多个对象时,可以使用集合
    // TODO 对象流
    		// 输出流 -> 序列化过程 : 将当前对象当中包含的信息(状态) -> 保存至文件当中
    		// 1-1.初始化对象输出流 -> 需要的参数 : 通用的输出流 -> FileOutputStream -> File -> 路径
    		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("E:/shop.txt")));
    		// 输入流 -> 反序列化过程 : 将文件当中存放的对象的信息 -> 返回一个对象(数据)
    		// 1-2.初始化对象输入流 -> 需要的参数 : 通用的输入流 -> FileInputStream -> File -> 路径
    		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("E:/shop.txt")));
    		// 2.获得一个自定义类的实例
    		Shop shop = new Shop("百货商厦");
    		// 3-1.序列化对象 - 自定义类实现序列化接口 - ID根据需要进行生成
    		outputStream.writeObject(shop);
    		// 3-2.反序列化 - 判断类型 - 强制转换接收
    		Object object = inputStream.readObject();
    		// 如果反序列化得到的对象是相应的实例
    		if (object instanceof Shop) {
    			// 检查是否成功反序列化
    			Shop newShop = (Shop)object;
    			System.out.println(newShop);
    		}
    		// 4.强制刷新
    		outputStream.flush();
    		// 5.关闭流
    		inputStream.close();
    		outputStream.close();
    
    //Product类中有引用数据类型变量Shop
    // TODO 对象流应用 - 对象的深度克隆
    		// 输出流 -> 序列化过程 : 将当前对象当中包含的信息(状态) -> 保存至文件当中
    		// 1-1.初始化对象输出流 -> 需要的参数 : 通用的输出流 -> FileOutputStream -> File -> 路径
    		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("E:/product.txt")));
    		// 输入流 -> 反序列化过程 : 将文件当中存放的对象的信息 -> 返回一个对象(数据)
    		// 1-2.初始化对象输入流 -> 需要的参数 : 通用的输入流 -> FileInputStream -> File -> 路径
    		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("E:/product.txt")));
    		// 2.获得一个自定义类的实例
    		Product oldProduct = new Product("商品1", 200, new Shop("商店1"));
    		// 3-1.序列化对象 - 自定义类实现序列化接口 - ID根据需要进行生成
    		outputStream.writeObject(oldProduct);
    		// 3-2.反序列化 - 判断类型 - 强制转换接收
    		Object object = inputStream.readObject();
    		// 如果反序列化得到的对象是相应的实例
    		if (object instanceof Product) {
    			// 检查是否成功反序列化
    			Product newProduct = (Product) object;
    			System.out.println(oldProduct);
    			System.out.println(newProduct);
    			oldProduct.setName("商品11");
    			newProduct.setName("商品2");
    			newProduct.getShop().setName("商店2");
    			System.out.println(oldProduct);
    			System.out.println(newProduct);
    		}
    		// 4.强制刷新
    		outputStream.flush();
    		// 5.关闭流
    		inputStream.close();
    		outputStream.close();
    
    public class Product implements Serializable {
    
    	public Product() {
    		
    	}
    
    	public Product(String name, Integer price) {
    		this.name = name;
    		this.price = price;
    	}
    	
    	public Product(String name, Integer price, Shop shop) {
    		this.name = name;
    		this.price = price;
    		this.shop = shop;
    	}
    
    	private String name;
    	// 封装类型比较时注意缓存机制以及手动拆箱
    	private Integer price;
    	// 成员变量中出现自定义类型,实例是一个引用类型
    	private Shop shop;
    
    	public Shop getShop() {
    		return shop;
    	}
    
    	public void setShop(Shop shop) {
    		this.shop = shop;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public Integer getPrice() {
    		return price;
    	}
    
    	public void setPrice(Integer price) {
    		this.price = price;
    	}
    
    	@Override
    	public String toString() {
    		return "Product [name=" + name + ", price=" + price + ", shop=" + shop + "]";
    	}
    
    public class Shop implements Serializable {
    	
    	private static final long serialVersionUID = -9099382180185766414L;
    
    	public Shop() {
    
    	}
    
    	public Shop(String name) {
    		this.name = name;
    	}
    
    	private String name;
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	@Override
    	public String toString() {
    		return "Shop [name=" + name + "]";
    	}
    	
    }
    

    1. 序列化

    • ObjectOutputStream
    • writeObject(Object obj):将对象写入流中

    2. 反序列化

    • ObjectInputStream
    • readObject():从流中读取对象
    // TODO 对象流应用 - 对象的深度克隆
    		// 输出流 -> 序列化过程 : 将当前对象当中包含的信息(状态) -> 保存至文件当中
    		// 1-1.初始化对象输出流 -> 需要的参数 : 通用的输出流 -> FileOutputStream -> File -> 路径
    		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File("E:/product.txt")));
    		// 输入流 -> 反序列化过程 : 将文件当中存放的对象的信息 -> 返回一个对象(数据)
    		// 1-2.初始化对象输入流 -> 需要的参数 : 通用的输入流 -> FileInputStream -> File -> 路径
    		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("E:/product.txt")));
    		// 2.获得一个自定义类的实例
    		Product oldProduct = new Product("商品1", 200, new Shop("商店1"));
    		// 3-1.序列化对象 - 自定义类实现序列化接口 - ID根据需要进行生成
    		outputStream.writeObject(oldProduct);
    		// 3-2.反序列化 - 判断类型 - 强制转换接收
    		Object object = inputStream.readObject();
    		// 如果反序列化得到的对象是相应的实例
    		if (object instanceof Product) {
    			// 检查是否成功反序列化
    			Product newProduct = (Product) object;
    			System.out.println(oldProduct);
    			System.out.println(newProduct);
    			oldProduct.setName("商品11");
    			newProduct.setName("商品2");
    			newProduct.getShop().setName("商店2");
    			System.out.println(oldProduct);
    			System.out.println(newProduct);
    		}
    		// 4.强制刷新
    		outputStream.flush();
    		// 5.关闭流
    		inputStream.close();
    		outputStream.close();
    

    三、标准输入输出流

    标准输入输出流是System.in和System.out,默认情况下代表键盘和显示器

    1. 输出流

    • PrintStream
    • setOut(PrintStream out):重新分配标准输出流
    // TODO 标准的输出流
    		PrintStream out = System.out;
    		System.out.println("123");
    		OutputStream outputStream = new FileOutputStream("E:/SystemTest.txt");
    		// 自定义输出路径 默认屏幕上
    		System.setOut(new PrintStream(outputStream));
    		System.out.println("456");
    		System.setOut(out);
    		System.out.println(456);
    

    2. 输入流

    • setIn(InputStream in):重新分配标准输入流
    // TODO 标准的输入流
    		InputStream in = System.in;
    		InputStream inputStream = new FileInputStream(new File("E:/SystemTest.txt"));
    		System.setIn(inputStream);
    		Scanner scanner = new Scanner(System.in);
    		// 使用Scanner实现文件内容读取
    		while (scanner.hasNext()) {
    			System.out.println(scanner.nextLine());
    		}
    		System.setIn(in);
    		scanner = new Scanner(System.in);
    		scanner.nextLine();
    		scanner.close();
    
    • 小练习
    // TODO 标准流练习
    		// 从键盘录入一组数据(字符串)
    		PrintStream out = System.out;
    		// (1)使用默认的标准输入流初始化一个Scanner对象
    		Scanner scanner = new Scanner(System.in);
    		// (2)定义一个集合用于存放接收到的字符串
    		List<String> list = new ArrayList<>();
    		int n = 4;
    		System.out.println("请输入四条数据:");
    		for(int i = 0;i < n;i ++) {
    			list.add(scanner.nextLine());
    		}
    		// 使用标准输出流写入到文件中
    		// (1)定义一个文件输出流 -> 指定到某一个文件
    		OutputStream outputStream = new FileOutputStream(new File("E:/SystemTest.txt"));
    		// (2)改变标准输出流的指向 -> 文件输出流
    		System.setOut(new PrintStream(outputStream));
    		// (3)遍历集合,使用println()方法输出集合元素
    		for (String line : list) {
    			System.out.println(line);
    		}
    		// 利用标准输入流实现使用Scanner读取文件中的内容,打印输出
    		// (1)定义一个文件输入流 -> 指定到数据记录文件
    		InputStream inputStream = new FileInputStream(new File("E:/SystemTest.txt"));
    		// (2)改变标准输入流的指向 -> 文件输入流
    		System.setIn(inputStream);
    		// (3)使用改变后的标准输入流初始化一个新的Scanner对象
    		scanner = new Scanner(System.in);
    		// (4)重置标准输出流 -> 显示器
    		System.setOut(out);
    		// (5)使用Scanner对象的nextLine()方法读取数据
    		while (scanner.hasNext()) {
    			System.out.println(scanner.nextLine());
    		}
    		scanner.close();
    
  • 相关阅读:
    golang 查询数据库并返回json
    logrus日志使用详解
    英文文章写作的一点个人思考
    AKS (1) AKS最佳实践
    Azure Application Insight (3) ASP.NET MVC增加Application Insight
    oracle 创建存储过程后,重新编译错误,如何查看错误信息
    ORACLE 存储过程IN关键字使用问题
    Oracle/for loop循环如何进行跳过、跳出操作
    (转)Golang struct{}的几种特殊用法
    (转)Golang 延迟函数 defer 详解
  • 原文地址:https://www.cnblogs.com/yokii/p/9441913.html
Copyright © 2020-2023  润新知