Java——IO流(字符流,字节流)

JavaIO的整体框架图

img

IO流从方向上来说,可以分为输入流和输出流;
从传输内容上来说,可以分为字符流和字节流

防止记混的口诀

所谓的IO,说白了就是数据在内存和硬盘之间的传输

输入流 = %Reader = %InputStream,从硬盘写入内存;
输出流 = %Writer = %OutputStream,从内存写入硬盘;

站在内存的角度,输入流是读入,输出流是写出;
站在硬盘的角度,输入流是读出,输出流是写入

我们为了防止记忆错乱,我建议站在内存的角度记忆,因为In和Out能对应上入和出

流 = %Reader = %InputStream = 内存

流 = %Writer = %OutputStream =

字符流

文本,我们能读的懂的都可以认为是字符流。比如:文章,java文件等等

字符流的本质是字符数组char[]

字符输入流的超类:
Reader: 子类FileReader,BufferedReader
字符输出流的超类:
Writer:子类FileWriter,BufferedWriter

字符流可以分为字符输入流Reader和字符输出流Writer

文件字符输入流FileReader

import java.io.*;public class ReaderTest {public static void main(String[] args) {File file = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTestPath\\hello.txt");File file2 = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTestPath\\charInput.txt");Reader reader = null;try {reader = new FileReader(file);// 1. 单个字符读取int c = reader.read();// 这样只能一个字符一个字符地读System.out.println((char)c);// 2. while循环读取while((c = reader.read()) != -1){System.out.print((char)c);}// 3. reader填充字符数组char[] cArr = new char[100];// 填充int len = reader.read(cArr);System.out.println("读取的长度:" + len + "    读取的内容:" + Arrays.toString(cArr));len = reader.read(cArr);System.out.println("第二次读取的长度:" + len + "    读取的内容:" + Arrays.toString(cArr));len = reader.read(cArr);System.out.println("第三次读取的长度:" + len + "    读取的内容:" + Arrays.toString(cArr));// 4. reader填充字符数组,并且拼接为字符串char[] cArr2 = new char[200];int len2 = -1;while ((len2 = reader.read(cArr2)) != -1) {String str = new String(cArr2, 0, len2 );System.out.println(str);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {//关闭资源if (reader != null) {try {reader.close();} catch (IOException e) {e.printStackTrace();}}}}
}

文件字符输出流FileWriter

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;public class WriterTest {public static void main(String[] args) {File file = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTestPath\\hello.txt");Writer writer = null;try {// 1. 直接write会删掉之前全部的,然后放进去新的writer = new FileWriter(file);writer.write("Hello 111Writer!!!");// 2. 在源文件后拼接字符流writer = new FileWriter(file, true);writer.write("append text!!!");// 3. 循环分段拼接字符流writer = new FileWriter(file, true);for (int i = 0; i < 100; i++) {writer.write("HelloWorld\n");//每次写入10个helloworld的时候做一次flushif (i % 10 == 0) {writer.flush();}}// 4. 字符数组(字符流)的直接输出(写入)File file2 = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTestPath\\charInput.txt");writer = new FileWriter(file2);//定义一个数组char[] c = {'a', 'b', 'p', 'b', 'p'};writer.write(c);writer.write("\r\n");writer.write(c, 2, 2);writer.write("\r\n");writer.write(98);writer.write("\r\n");writer.write("我们今生注定是沧桑", 2, 6);} catch (IOException ioe) {ioe.printStackTrace();} finally {//判断writer不是空防止空指针异常if (writer != null) {try {//关闭流writer.close();} catch (IOException e) {e.printStackTrace();}}}}
}

注意:一般的writer会将原内容删除,再写新内容;如果想要在原有内容的基础上填充,就需要让append为true

Writer writer = new FileWriter(file, true);
flush方法是干什么的?

writer.flush()的作用在于将缓冲区的所有字符都发送给硬盘

只有Writer和OutputStream才有flush方法;但是不管读写都有自己的缓冲区,只不过读操作不需要我们手动清空缓冲区罢了

java在使用流时,都会有一个缓冲区,按一种它认为比较高效的方法来发数据:把要发的数据先放到缓冲区,缓冲区放满以后再一次性发过去,而不是分开一次一次地发.
而flush()表示强制将缓冲区中的数据发送出去,不必等到缓冲区满.

执行close()方法时,会强制执行一次flush()方法

但是如果忘了使用close(),也没有用flush()这个方法,很多情况下会出现流的另一边读不到数据的问题,特别是在数据特别小的情况下

我们测试用的数据都是很少的,FileWriter默认的缓冲区大小是8KB,显然到不了这个长度

为什么需要缓冲区(重点)

因为内存与硬盘的读写操作比较耗费时间,为了减少内存与磁盘的交互次数,降低时间消耗,我们使用缓冲区缓存一部分内容,只有缓冲区满了才会向硬盘发送写请求,这样做可以减少交互次数,降低耗时

使用FileReader和FileWriter完成文件拷贝
import java.io.*;public class CopyFileTest {public static void main(String[] args) throws IOException {File file = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTestPath\\hello.txt");Writer writer = new FileWriter("helloCopy.txt", true);Reader reader = new FileReader(file);// 清空之前的内容writer.write("");// 一字节一字节地读取char[] cArr = new char[1024];int len = -1;while ((len = reader.read(cArr)) != -1) {String str = new String(cArr, 0, len);// 读到的字符串写入文件中writer.write(cArr, 0, len);writer.flush();}if (reader != null) {reader.close();}if (writer != null) {writer.close();}}
}

缓冲字符输入流BufferedReader

public class BufferReaderTest {public static void main(String[] args) {File file = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTestPath\\charInput.txt");BufferedReader bufferedReader = null;try {bufferedReader = new BufferedReader(new FileReader(file));String line = null;// BufferedReader是一行一行读取的while((line = bufferedReader.readLine()) != null){//打印一行System.out.println(line);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//关闭外层的对象的时候,内存的资源会自动的被关闭if(bufferedReader != null){try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}}}
}

BufferedReader读取数据是一行一行地读的

之前说过Reader和Writer都有自己的缓冲区,BufferedReader和FileWriter的缓冲区大小相同,区别在于BUfferedWriter只有缓冲区满了才会进行字符转码(将字符转化为字节)

缓冲字符输出流BufferedWriter

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;public class BufferWriterTest {public static void main(String[] args) {File file = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTestPath\\charInput.txt");BufferedWriter bufferWriter = null;try {bufferWriter = new BufferedWriter(new FileWriter(file, true));bufferWriter.write("BufferedWriter写入的内容:11111");//换行bufferWriter.newLine();bufferWriter.write("BufferedWriter写入的内容:22222");bufferWriter.flush();} catch (IOException e) {e.printStackTrace();} finally {//资源关闭if (bufferWriter != null) {try {bufferWriter.close();} catch (IOException e) {e.printStackTrace();}}}}
}
使用BufferedReader和BufferedWriter完成文件拷贝

原理同上,写法不同

import java.io.*;public class BufferedCopyFile {public static void main(String[] args) {File file = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collection-test\\src\\FileTestPath\\charInput.txt");BufferedReader bufferedReader = null;BufferedWriter bufferWriter = null;try {bufferedReader = new BufferedReader(new FileReader(file));String line = null;// BufferedReader是一行一行读取的while ((line = bufferedReader.readLine()) != null) {bufferWriter = new BufferedWriter(new FileWriter("bufferedCopyFile.txt", true));bufferWriter.write(line);bufferWriter.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//关闭外层的对象的时候,内存的资源会自动的被关闭if(bufferedReader != null){try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}//资源关闭if (bufferWriter != null) {try {bufferWriter.close();} catch (IOException e) {e.printStackTrace();}}}}
}
Buffered为什么高效?

在这里插入图片描述
在这里插入图片描述
所有的Writer字符流,都要先变成InputStreamReader/OutputStreamWriter,然后转化为InputStream/OutputStream变成字节数组,最终转化为二进制数据才能在计算机底层进行传输

所有的Reader字符流,过程相反
我们可以看到,字符流读写存在编解码的过程,而Buffered之所以高效,就是因为FileWriter每次调用write()方法,就会调用一次OutputStreamWriter中的write()方法,而BufferedWriter只有在缓冲区满了才会调用OutputStreamWriter中的write()方法。

打印字符输出流PrintWriter

PrintWriter和FileWriter之间的区别

区别在于 :

  1. PrintWriter设计之初就是为了写出,所以没有PrintReader
  2. PrintWriter 提供了一些额外的格式化方法,如 println ,print和 printf,而且可以将内容打印到控制台上
  3. 封装了字符输出流,还可以字符流和字节流的转换
  4. 可以打印各种数据类型
  5. PrintWriter 在传递流时所做的是以 缓冲(BufferedWriter) 方式打开它,FileWriter不是
  6. 与 PrintStream 类不同,如果启用了自动刷新,但只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作(PrintStream是任何写方法都可以自动刷新)
PrintWriter(Writer out, boolean autoFlush);// true开启,false关闭
public PrintWriter(File file) throws FileNotFoundException {this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),false);
}

FileWriter没有缓冲

public FileWriter(File file) throws IOException {super(new FileOutputStream(file));
}
demo

打印控制台

        PrintWriter pw = null;BufferedReader br = null;try {br = new BufferedReader(new FileReader("c.txt"));pw = new PrintWriter("d.txt");String line = null;while((line = br.readLine()) != null){pw.println(line);pw.flush();}} catch (Exception e) {e.printStackTrace();} finally {if(pw != null){pw.close();}if(br != null){try {br.close();} catch (IOException e) {e.printStackTrace();}}}

打印到文件中(其实就是向文件中写)

        PrintWriter pw = null;try {pw = new PrintWriter("c.txt");pw.println(1);pw.println(1.1);pw.println("liangge");pw.println('c');pw.println(false);pw.println(1.2f);pw.flush();} catch (FileNotFoundException e) {e.printStackTrace();} finally {if(pw != null){pw.close();}}

字节流

二进制的数据,这种数据一般用文本打开我们读不懂。比如,图片文件,mp3文件。

字节输入流的超类:InputStream:
子类:FileInputStream
字节输出流的超类:
OutputStream:
子类FileOutputStream

字节流传输的是二进制的数据

字节流的本质是字节数组byte[]

字符流能传输的,字节流也可以传输;
字节流能传输的,字符流不一定能传输

文件字节输入流FIleInputStream

public static void main(String[] args) {//创建字符输入流的对象InputStream in = null;try {in = new FileInputStream("a.txt");int r = in.read();System.out.println((char)r);} catch (Exception e) {e.printStackTrace();} finally {if(in != null){try {in.close();} catch (IOException e) {e.printStackTrace();}}}}

文件字节输出流FIleOutputStream

public class IOByteDemo {public static void main(String[] args) {//创建字节输出流OutputStream out = null;try {out = new FileOutputStream(new File("a.txt"));//字节流不需要flushout.write(98);// Ascii码对应的是小写字母b} catch (Exception e) {e.printStackTrace();} finally {try {if(out != null){out.close();}} catch (IOException e) {e.printStackTrace();}}}
}

缓冲字节输入流BufferedInputStream

public static void main(String[] args) throws IOException {File file = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collectionAndIOStream-test\\helloCopy.txt");// 以下两种方式均可// BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()));BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));byte[] bytes = new byte[1024];int len = -1;while ((len = bis.read(bytes)) != -1) {String s = new String(bytes, 0, len);System.out.print(s);}}

比BufferedReader更快,因为不需要转化为InputStreamReader,但是仍然需要编码

缓冲字节输入流BufferedOutputStream

    public static void main(String[] args) throws IOException {File file = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collectionAndIOStream-test\\buf.txt");// 以下两种方式均可// BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(file.toPath()));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));//创建一个字节的数组byte[] bs = {97, 99, 103, 111};bos.write(bs, 1, 2);}

比BufferedWriter更快,因为不需要转化为OutputStreamWriter,但是仍然需要解码

BufferedStream拷贝文件
public static void main(String[] args) throws IOException {File fileRead = new File("D:\\2_WorkSpace\\qcbyProject\\shixun\\collectionAndIOStream-test\\helloCopy.txt");File fileWrite = new File("bisAndBos.txt");BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileRead));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileWrite));int count = 0;while (count == 0) {count = bis.available();}int fileSize = bis.available();long written = 0;int beteSize = 1024;byte[] bytes = new byte[beteSize];while (written < fileSize) {if (written + beteSize > fileSize) {beteSize = (int) (fileSize - written);bytes = new byte[beteSize];}bis.read(bytes);bos.write(bytes);bos.flush();written += beteSize;}}

对象字节输出流ObjectOutputStream(序列化流)

对象转化为二进制数据,被称为序列化;
将二进制数据转化为对象,被称为反序列化

我们假设有这样一个Person

必须实现Serializable接口!!!

public class Person implements Serializable{//唯一的序列化接口的id值private String name;private int age;private Date birth;private static final long serialVersionUID = 3587752576949978144L;private String addr;public Person(String name, int age, Date birth) {this.name = name;this.age = age;this.birth = birth;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Date getBirth() {return birth;}public void setBirth(Date birth) {this.birth = birth;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", birth=" + birth +", addr='" + addr + '\'' +'}';}
}

对象流进行序列化

public static void main(String[] args) {Person p = new Person("宇智波止水", 16, new Date());ObjectOutputStream out = null;try {out = new ObjectOutputStream(new FileOutputStream("person-data.txt"));out.writeObject(p);out.flush();} catch (IOException e) {e.printStackTrace();} finally {if(out != null){try {out.close();} catch (IOException e) {e.printStackTrace();}}}}

txt内容
在这里插入图片描述

对象字节输入流ObjectInputStream(反序列化流)

把我们刚才序列化的字节序列反序列化为java对象

public static void main(String[] args) {ObjectInputStream in = null;try {in = new ObjectInputStream(new FileInputStream("person-data.txt"));//读取一个对象, 叫反序列化Object o = in.readObject();System.out.println(o);} catch (Exception e) {e.printStackTrace();} finally {if(in != null){try {in.close();} catch (IOException e) {e.printStackTrace();}}}}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/29023.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#——类和对象详情

类和对象 类 类是一种数据结构&#xff0c;它可以包含数据成员&#xff08;常量和字段&#xff09;、函数成员&#xff08;方法、属性、事件、索引器、运算符、实例构造函数、静态构造函数和析构函数&#xff09;以及嵌套类型。类类型支持继承&#xff0c;继承是一种机制&…

在 Selenium 中更改 User-Agent | 步骤与最佳实践

在 Selenium 中更改 User Agent 是许多网页抓取任务中的关键步骤。它有助于将自动化脚本伪装成常规浏览器&#xff0c;从而避免被网站检测到。本指南将带您了解如何在 Selenium 中更改 Google Chrome 的 User Agent&#xff0c;并提供最佳实践以确保您的网页抓取任务顺利进行。…

湿法消解石墨消解仪 应用化学分析领域石墨炉

石墨消解仪在化学实验中具有重要的作用。它是一种高级实验设备&#xff0c;广泛应用于化学分析领域&#xff0c;特别是在样品的前处理和测试前的样品制备过程中。 石墨消解仪采用高温高压技术&#xff0c;能够将固体样品中的有机和无机物质转化为可溶性的气体或液体形式。这种…

从0进入微服务需要了解的基础知识

文章目录 系统架构演化过程为什么要了解系统架构的演化过程技术发展认知技术选型与创新 演变过程单体架构分层-分布式集群微服务 分布式\集群\微服务 微服务中的核心要素-拆分原则项目拆分与复杂度微服务的拆分维度有哪些小结 微服务中的核心要素服务化进行拆分后一定是微服务&…

可通过小球进行旋转的十字光标(vtkResliceCursor)

前一段事件看到VTK的一个例子&#xff1a; 该案例是vtk.js写的&#xff0c;觉得很有意思&#xff0c;个人正好也要用到&#xff0c;于是萌生了用C修改VTK源码来实现该功能的想法。原本以为很简单&#xff0c;只需要修改一下vtkResliceCursor就可以了&#xff0c;加上小球&#…

自动生成列表,颜色随机 ,定时执行函数,10秒停止执行函数,按钮执行函数

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>颜色列表Color List</title><style>…

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[4]-高阶自定义模块

基于LangChain-Chatchat实现的RAG-本地知识库的问答应用[4]-高阶自定义模块 1.自定义分词器 在text_splitter文件夹下新建一个文件,文件名为您的分词器名字,比如my_splitter.py,然后在__init__.py中导入您的分词器,如下所示:from .my_splitter import MySplitter修改confi…

新课程《新课程》期刊是什么级别的刊物?

新课程《新课程》期刊是什么级别的刊物&#xff1f; 《新课程》是由山西出版传媒集团主管、山西三晋报刊传媒集团主办的教育类学术期刊&#xff0c;属于省级刊物。 该期刊的国内刊号为CN14-1324/G4&#xff0c;国际刊号为ISSN1673-2162。 其主要栏目包括教育教学类、课程篇、…

厂里教务之延迟任务精准发布文章

延迟任务精准发布文章 延迟任务概述 什么是延迟任务 定时任务&#xff1a;有固定周期的&#xff0c;有明确的触发时间 延迟队列&#xff1a;没有固定的开始时间&#xff0c;它常常是由一个事件触发的&#xff0c;而在这个事件触发之后的一段时间内触发另一个事件&#xff0c…

部署远程控制台访问服务Rttys,第三部分服务端(安装Rttys)

安装服务端Rttys之前可选先在客户端安装rtty。服务端采用GO语言实现&#xff0c;前端界面采用vue实现。 CMAKE的安装和客户端RTTY的安装请参考前两篇文章&#xff1a; Linux远程连接程序工具选型 Webssh与Rtty 部署远程控制台访问服务Rttys&#xff0c;第一部分客户端&#…

下饺子模式一触即发,爆款的诞生仿佛“开盲盒”?

千呼万唤始出来&#xff0c;国产首款3A游戏大作《黑神话&#xff1a;悟空》即将发售。 早在2020年的8月20日当天&#xff0c;《黑神话&#xff1a;悟空》就发布了13分钟的实机演示。仅两天&#xff0c;B站播放量超过1700万&#xff0c;微博话题阅读量超过2.4亿。 从立项开始算…

自动化产线设备联网,协同打造5G智慧工厂

1、需求背景 随着信息技术、物联网、人工智能等领域的飞速发展&#xff0c;智慧工厂成为制造业升级和转型的关键方向。在智慧工厂中&#xff0c;产线设备之间的实时通信和协同操作可以提高整个生产流程的自动化水平。 提升生产效率 通过稳定的网络连接&#xff0c;保证设备之…

RT-Thread简介及启动流程分析

阅读引言&#xff1a; 最近在学习RT-Thread的内部机制&#xff0c;觉得这个启动流程和一些底层原理还是挺重要的&#xff0c; 所以写下此文。 目录 1&#xff0c; RT-Thread简介 2&#xff0c;RT-Thread任务的几种状态 3&#xff0c; 学习资源推荐 4&#xff0c; 启动流程分…

MTANet: 多任务注意力网络,用于自动医学图像分割和分类| 文献速递-深度学习结合医疗影像疾病诊断与病灶分割

Title 题目 MTANet: Multi-Task Attention Network for Automatic Medical Image Segmentation and Classification MTANet: 多任务注意力网络&#xff0c;用于自动医学图像分割和分类 01 文献速递介绍 医学图像分割和分类是当前临床实践中的两个关键步骤&#xff0c;其准…

Springboot3+自动装配

导言&#xff1a;这里主要讲述springboot3以后spring.factories功能失效&#xff0c;带来的解决办法。 之前有一次希望用springboot模块拿到工具模块的配置configuration的时候&#xff0c;想通过之前的spring.factories来实现自动装配&#xff0c;但是发现一直拿不到配置&…

数据仓库与数据挖掘(期末复习)

数据仓库与数据挖掘&#xff08;期末复习&#xff09; ETL的含义Extract 、 Transformation、Load。 ODS的全称Operational Data Store。 DW全称 Data Warehourse DM全称是Data Mart 数据仓库数据抽取时所用到技术是增量、全量、定时、调度 STAGE层作用是提供业务系统数据…

全国各区县地区生产总值数据(GDP及人均生产总值),精度超高 区县级数据

数据名称: 全国各区县地区生产总值数据 数据格式: shpexcel 数据几何类型: 面 数据精度&#xff1a;区县 数据坐标系: WGS84 数据来源&#xff1a;网络公开数据 数据可视化.

稳了?L3规模化落地在即,激光雷达公司成首批赢家

作者 | 芦苇 编辑 | 德新 在中国&#xff0c;距L3级自动驾驶的规模化落地&#xff0c;又近了一步。 随着国内试点政策刷新&#xff0c;越来越多的车企在部分市域获得了自动驾驶测试牌照&#xff0c;能上路测试的L3级自动驾驶车辆正在快速增加。 其中一个重要节点是&#xf…

C语言最终文章-二叉树

文章目录 前言二叉树的性质二叉树的存储方式顺序存储堆及其应用TopK问题堆排序 链式存储二叉树的练习1.二叉树查找值为x的节点2.判断是否为完全二叉树LC226.翻转二叉树[LC572. 另一棵树的子树](https://leetcode.cn/problems/subtree-of-another-tree/description/)两道选择题 …

目标检测:IOU

IOU&#xff08;Intersection over Union&#xff09;交并比&#xff1a; 它计算的是“预测的边框”和“真实的边框”的交叠率&#xff0c;即它们的交集和并集的比值。这个比值用于衡量预测边框与真实边框的重叠程度&#xff0c;从而评估目标检测的准确性。 在目标检测任务中…