Java IO流详解和常用流的使用
文章目录
- 一, IO概念
- 二, "流" 是什么?
- 三, IO流的分类
- 3.1 从流的方向来看
- 3.2 按照流的操作粒度划分
- 3.3 按照流的角色划分
- 四, IO流体系的概览和使用
- 4.0 文件类(File)对象的使用
- 4.1 字节流中常用的几种实现类
- 4.1.1 FileInputStream 和 FileOutputStream 的使用
- 4.1.2 FileInputStream
- 4.1.2 FileOnputStream
- 4.1.2 BufferedInputStream 和 BufferedOutputStream 的使用
- 4.1.3 字节流中常用读写方法总结
- 4.2 字符号流中常用的几种实现类
- 4.2.1 FileReader 和 FileWriter 的使用
- 4.2.1.1 FileReader
- 4.2.1.2 FileWrite
- 4.2.1.3 FileReader 和 FileWriter 的简单示例
- 4.2.2 BufferedReader 和 BufferedWriter的使用
- 4.2.2.1 BufferedReader
- 4.2.1.3 BufferedReader 和 BufferedWriter的简单示例
- 4.3 字符流中常用方法总结
- 4.3.1 两张图让你记住字节流, 字节流的纷繁复杂关系
- 4.4 序列化(ObjectInputStream && ObjectOutputStream)
- 4.5 附录一, 字母和汉字在不同字符集中的占位
一, IO概念
- I/O 即输入Input/ 输出Output的缩写, 值指的是应用程序和外部设备之间的数据传递, 常见的外部设备包括文件, 管道, 网络连接;
二, “流” 是什么?
Java 是通过流来处理IO的, 那什么是流呢?
流(Stream), 是一个抽象的概念, 指的是一个以先进先出方式发送信息的通道, 发送的信息是一连串的字符或字节数据;
- 当程序需要
读取数据
的时候, 就会开启一个通向数据源的流(即输入流), 这个数据源可以是文件, 内存, 或是网络连接; - 类似的, 当程序需要
写出数据
的时候, 就会开启一个通向目的地的流(即输出流). - 这样来看, 数据就像是在应用程序和外部设备之间流动一样, 所以叫流.
一般来说, 关于流的特性有下面几点:
- 先进先出:最先写入输出流的数据最先被输入流读取到。
- 顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile除外)
- 只读或只写:
每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。
在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。
三, IO流的分类
3.1 从流的方向来看
- 注意:
输入和输出都是从应用程序的角度划分的
!
输入流: 读取文件到程序的流, 主要以
InputStream
和Rearder
作为基类;
输出流: 从程序写出到外部设备的流, 主要以
OutputStream
和Writer
作为基类;
3.2 按照流的操作粒度划分
字节流: 以字节为单元, 可操作任何数据, 字节流主要由InputStream和outPutStream作为基类
字符流: 以字符为单元, 只能操作纯字符数据,比较方便, 字符流主要由Reader和Writer组颇为基类
字节流和字符流的用法几乎完成全一样,区别在于字节流和字符流所操作的数据单元不同,字节流操作的单元是数据单元是8位的字节,字符流操作的是数据单元为16位的字符。
3.3 按照流的角色划分
节点流: 直接操作数据读写的流类,比如FileInputStream 可以 从/向 一个特定的IO设备(如磁盘, 网络) 读/写 数据的流, 也叫低级流(主要流);
处理流: 对一个已存在的流的链接和封装,通过对数据进行处理为程序提供功能强大、灵活的读写功能,例如BufferedInputStream(缓冲字节流) 也叫高级流;
补充说明:
四, IO流体系的概览和使用
- java.io中子类有40个“流”类, 我们只需要掌握其中常用的几个即可. 其他的用到了再去翻API.
4.0 文件类(File)对象的使用
- Java中用文件类 File 指代文件系统中的文件/目录, 自然的, 实例化File文件类的文件对象, 拥有着一系列操纵文件和目录的方法;
- File对象既可以表示文件,也可以表示目录。特别要注意的是,构造一个File对象,即使传入的文件或目录不存在,代码也不会出错,因为
构造一个File对象,并不会导致任何磁盘操作。只有当我们调用File对象的某些方法的时候,才真正进行磁盘操作。
File类的具体方法和使用: 详见此文Java中的File类及其常用方法详解
4.1 字节流中常用的几种实现类
前面我们提到, 字节流可以处理任何形式的文件, 在字节流中, 文件是以一个个字节的形式流动的, 我们在使用字节流的具体实现类对象时, 也是通过调用read() 或 write() 对这些字节进行操作的.
4.1.1 FileInputStream 和 FileOutputStream 的使用
4.1.2 FileInputStream
[API中常用方法介绍]
也许有人经常会对具体使用时read的返回值有些许困惑,请仔细阅读下面的代码示例:
@Testpublic void fisTest() thorws IOException{//新建File类对象, 操纵文件输入流, 从文件中读取数据///ctrl+alt+f--> idea 把局部变量变为全局变量的快捷键File file = new File("e://fis.txt");FileInputStream fis = new FileInputStream(file);//1.1. 一个字节一个字节的读取数据// Q: read() 是如何读取字节的?// read() 读取返回的是字节的ASCII码, 而 read(byte[])读取返回的是读取完的字节数组的长度;int read = 0;while((read = fis.read()) != -1){ //每从数据流中读取一次就返回一个字节的数据, 当读取到数据末尾时, 返回值为 -1System.out.print(read + "--" + (char)read);System.out.println();}System.out.println("=======================================");//1.2 把读取的字节放入字节数组, 然后直接返回字符串byte[] bytes = new byte[12];int dataLen = fis.read(bytes); //fis.read(bytes) 返回的结果是字节的总长度System.out.println("dataLen = "+dataLen);System.out.println(new String(bytes, 0, dataLen-1));//别忘了关流! fis.close();}
总结:
- 正如API中说明的那样, int read() **由代表输入流的类对象调用, 每从数据流中读取一次就返回一个字节的数据, 当读取到数据末尾时, 返回值为 -1 ** ,经验证, 返回的实际数据是ASCII码的十进制值. 正如上图所示, 前面是 fis.read() 实际返回的ASCII 值, 后面的经过强制类型装转换后的真正数据.
- 由于一个字节一个字节的读取数据并输出效率实在太低, 我们可以使用 int read(bytes[] b) , 把读取到的字节全部放入到指定的字节数组b中, 这里要注意, read(byte[] b) 方法一次性返回数据对应的字节长度, 如果读取到数据末尾同样也是返回 -1;
4.1.2 FileOnputStream
[API中常用方法介绍]
- 如果我们是要追加写入到文件(即写入到文件中数据的末尾), 那么在创建输出流对象时, 使用下面的构造方法即可;
代码示例如下:
public class FileCopy_1 {@Testpublic void copyTest() throws IOException {//1. 创建文件类对象,传入文件路径String filePath = "e://source.jpg";File file = new File(filePath); //旧文件String target_filePath = "d://target.jpg";File target_file = new File(target_filePath);//2. 创建输入流, 读取磁盘的文件到内存FileInputStream fis = new FileInputStream(file);//3. 创建输出流, 写出文件数据到其他目录的文件中FileOutputStream fos = new FileOutputStream(target_file);//4. 输入流读取文件到内存, 再由输出流把内存中的字节数据写入到磁盘文件.//这样就完成了一次文件复制, 为了提高效率, 我们可以采取边读入边写出的方式int read = 0;while((read = fis.read()) != -1){System.out.println("文件正在复制中, 请等待....");fos.write(read);}System.out.println("文件复制成功!");//5. 上面即便是同时复制, 效率还是非常低的, 只能一个字节一个字节的复制.//下面我们采用字节数组存储要复制的数据, 当输入流读取完毕后, 由输出流把字节数组写出到磁盘byte[] buf = new byte[102400 * 7]; //700kbint dataLen = fis.read(buf);fos.write(buf, 0, dataLen);}
4.1.2 BufferedInputStream 和 BufferedOutputStream 的使用
缓冲字节流是包装流, 是对FileInput(output)Stream的包装, 仅仅是在他们的基础上加入了缓存机制, 底层的读写操作还是由FileInput(output)Stream 类对象完成的, 所以其构造方法入参是这两个类的对象也就不奇怪了。
@Testpublic void testWriteBufferOutputStream() throws IOException {//1. 创建文件对象File file = new File("e://res.txt");//2. 使用文件对象创建新文件//file.createNewFile();//3. 使用输出缓冲流写出给定数据到文件String outStr = "dududu, hello, are u sb? ";//4. 创建文件输出流, 底层操控文件的写出FileOutputStream fos = new FileOutputStream(file);//5. 使用缓冲输出流包装文件输出流, 为什么包装? 包装的意义何在?// 把写出的数据放入到缓存中, 到达一定的限度才写出到磁盘, 降低了cpu占用和磁盘IO//而且由于是缓存(内存) 写出到磁盘, 肯定速度要快很多BufferedOutputStream bos = new BufferedOutputStream(fos);bos.write(outStr.getBytes(StandardCharsets.UTF_8));System.out.println("写出成功!");// 关闭流, 释放资源, 很重要!bos.close();}@Testpublic void testBufferedInputStream() throws IOException {//1. 创建文件对象String pathName = "e://res.txt";File file = new File(pathName);//2. 创建FIS对象FileInputStream fis = new FileInputStream(file);//3. BufferedInputStream 只是对FileInputStream的一个包装流, 底层读取依靠的仍旧是fis.//创建bis也就需要fis的对象.BufferedInputStream bis = new BufferedInputStream(fis);//4. 使用bis读取数据(一个字节一个字节的读取)int read = 0;while((read = bis.read()) != -1){System.out.print((char)(read) + "");}System.out.println("==================================");//5. 使用字节数组读取byte[] bytes = new byte[1024];int dataLen = bis.read(bytes);System.out.println(new String(bytes, 0, dataLen));//关闭流bis.close();}
4.1.3 字节流中常用读写方法总结
4.2 字符号流中常用的几种实现类
要特别注意到: 在字符流中, 我们常用的一些流, 比如 FileReader, FileReader, BUffer
4.2.1 FileReader 和 FileWriter 的使用
4.2.1.1 FileReader
字符流 FileReader/ FileWriter 类结构稍微复杂一些, 但是每个类都有着明确不同的职责, 我们先拿读入流来梳理一下这些类,
继承结构: Reader(抽象类) <-- InputStreamReader(字节和字符转换的桥梁)<— FileReader (方便类, 直接对字符流进行操作)
先来看 Reader:
再来看 InputStreamReader:
最后来看 FileReader:
- 为什么前面我们说 FileReader 是读取字符流的方便类? 方便在哪里呢?
- 我们知道, InputStreamReader/Writer 是字符流和字节流的桥梁, 通过此类, 我们可以读取字节, 使用指定字符集转换为字符, 那么使用这个类是如何获得字符流呢? new InputStreamReader( new FileInputStream(file, true), UTF-8) , 是不是很麻烦?
- 当我们使用 Filerader 获取字符流, 只需要 new FileRader(file) 即可, 方便吧, 就是不能通过这种方法指定字符集;
4.2.1.2 FileWrite
[API中常用方法介绍]
上面我们讲了 FileReader 的继承结构, 和每个类的用处, FileWrite 跟它是基本一模一样的, 所以这节说下FileWrite的几个方法
继承结构: Writer <-- InputStreamWriter <— FileWriter
- 对于FileWrite 和 FileReader 的方法, 其实他俩分别就只有俩构造方法, 其他的方法都是继承自他的父类 InputStreamWrite 和 OutputStreamReader, 并且完全没有重写, 直接调用的!
4.2.1.3 FileReader 和 FileWriter 的简单示例
@Testpublic void testFileReader() throws IOException {//Reader 接口--> InputStreamReader(字节流转为字符流) --> FileReader(字符流)//1. 新建文件类对象File file = new File("d:\\file.txt");//2. 新建字符读入流FileReader fileReader = new FileReader(file);//3. 一个字节一个字节的读取字节int read = 0;while((read = fileReader.read()) != -1){System.out.print((char)read);}//4. 提高效率, 把读取的字节放入到char数组,统一返回char[] chaArr = new char[1024];int dataLen = fileReader.read(chaArr);System.out.println(new String(chaArr, 0, dataLen));//关流fileReader.close();}@Testpublic void testFileWriter() throws IOException {// Writer <--- InputStreamWriter <--- FileWriter//1. 创建文件对象File file = new File("e:\\target1.txt");//file.createNewFile();//2. 创建FileWriter 对象, 传入文件对象FileWriter fw = new FileWriter(file);//3. 待写入字符串String outStr = "我这里可是字符串, 我会被InputStream转换为字节流 ?";//4. 写出fw.write(outStr);//5. 关闭fw.close();}
4.2.2 BufferedReader 和 BufferedWriter的使用
4.2.2.1 BufferedReader
[API 方法说明: ]
对于上面两种方法, 底层都是读取的字节流, 即都是使用了FileInputStream 获取字节流, 然后经过处理转换成字符流, 存放到缓存中;
对于包装类BufferedReder, 可以包装Reader的任何子类, 即可以为任何Reader的子类加上缓冲区;
实际上, BufferedReader 只是一个采用了装饰器设计模式的包装流, 他可以借助构造器读取IO流中Reader 的任何子类, 把这些子类对象读取或者写入的字节流或字符流放入到缓存中.
所有方法:
4.2.1.3 BufferedReader 和 BufferedWriter的简单示例
public class BufferedReaderDemo {@Testpublic void testBufferedReader() throws IOException {//从文件中读取字节, 把字节转换为字符, 为这个字符加上缓冲区,// 每个缓冲区满了之后才向应用程序提交//1. 新建文件对象, 传入相应的文件路径File file = new File("d:\\file.txt");//2. 读取缓冲流是缓冲流, 对结点流进行包装FileReader fr = new FileReader(file);//两种写法殊途同归. 都行//BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));BufferedReader br = new BufferedReader(fr);/////3. 按字节读取int read = 0;while ((read = br.read()) != -1) {System.out.print((char) read);}//3.1 按char 字符数组读取char[] charArr = new char[1024];int dataLen = br.read(charArr);System.out.println(new String(charArr, 0, dataLen));4. 按行读取String sb = null;while((sb = br.readLine()) != null){System.out.println(sb);}//关流br.close();}@Testpublic void testBufferedWriter() throws IOException {//1. 新建文件对象, 传入相应的文件路径File file = new File("e:\\target1.txt");//2. 读取缓冲流是缓冲流, 对结点流进行包装FileWriter fr = new FileWriter(file);//3. 创建写出缓冲流BufferedWriter bw = new BufferedWriter(fr);//4. 写出字符串String outStr = "译文\n" +"人生如果都像初次相遇那般相处该多美好,那样就不会有现在的离别相思凄凉之苦了。\n" +"如今轻易地变了心,你却反而说情人间就是容易变心的。\n" +"想当初唐皇与贵妃的山盟海誓犹在耳边,却又最终作决绝之别,即使如此,也生不得怨。\n" +"但你又怎比得上当年的唐明皇呢,他总还是与杨玉环有过比翼鸟、连理枝的誓愿。\n" +"\n" +"注释\n" +"柬:给……信札。\n" +"“何事”句:用汉朝班婕妤被弃的典故。班婕妤为汉成帝妃,被赵飞燕谗害,退居冷宫,后有诗《怨歌行》,以秋扇闲置为喻抒发被弃之怨情。南北朝梁刘孝绰《班婕妤怨》诗又点明“妾身似秋扇”,后遂以秋扇见捐喻女子被弃。这里是说本应当相亲相爱,但却成了相离相弃。\n" +"故人:指情人。却道故人心易变(出自娱园本),一作“却道故心人易变”。\n" +"“骊山”二句:用唐明皇与杨玉环的爱情典故。《太真外传》载,唐明皇与杨玉环曾于七月七日夜,在骊山华清宫长生殿里盟誓,愿世世为夫妻。白居易《长恨歌》:“在天愿作比翼鸟,在地愿作连理枝。”对此作了生动的描写。后安史乱起,明皇入蜀,于马嵬坡赐死杨玉环。杨死前云:“妾诚负国恩,死无恨矣。”又,明皇此后于途中闻雨声、铃声而悲伤,遂作《雨霖铃》曲以寄哀思。这里借用此典说即使是最后作决绝之别,也不生怨。\n" +"薄幸:薄情。锦衣郎:指唐明皇。▲";bw.write(outStr, 0, outStr.length());//注意这个bufferedwriter的特别之处, 必须得手动刷写, bw.flush();bw.flush();}
}
4.3 字符流中常用方法总结
4.3.1 两张图让你记住字节流, 字节流的纷繁复杂关系
- 记住. 在IO流中, IO流的最高抽象
基类
, 在字节流中, 叫 InputStream 和 OutputStream, 在字符流中, 叫 Reader 和 Writer, 而真正真正实现读或写方法, 真正操纵字节流或字符流
, 我们也叫低级流(节点流), 是继承了基类的流, 比如操纵文件的FileInputStream, 读对象的ObjectStream等等, 对其进行包装的流, 如BufferedInputSream, 我们叫高级流;- 对于字节流, 当我们要对文件读取字节时, 使用继承了InputStream抽象类的FileInputSream中的read()方法, 或者当我们要读取对象时, 使用继承了InputStream抽象类的ObjectInputStream中的read()方法, 如果我们想提高读取字节的速度, 我们可以使用缓冲字节输入流BufferInStream()包装节点流去读取文件或对象;
- 对于字符流的读写, 我们通常是
使用字节流读取文件, 然后使用一个类 InputSreamReader把字节流转换为字符流返回
, 比如 new InputStreamReader(new FileInputStream(new File(path), true), 字符集),- 这样也太特么的麻烦了吧, 各种构造器的传参, 所以我们的字符流有一个方便类, 一个new就可以实现上述的功能. new FileReader(file) , 就是不能通过这种方法指定字符集
- 同样的, 如果我们想提高字符流的读取速度, 仍然是通过缓冲流去包装节点流, 字符流的包装刘叫BufferedReader.
4.4 序列化(ObjectInputStream && ObjectOutputStream)
序列化和反序列化: 持久化存储, 网络传输
待补充
4.5 附录一, 字母和汉字在不同字符集中的占位
- 参考文章:
- https://blog.csdn.net/mu_wind/article/details/108674284
- b 站韩顺平
- https://juejin.cn/post/6850418112567869447#heading-0
Java IO流详解和常用流的使用相关推荐
- java IO编程详解
java IO编程详解 一.Socket 1. Sock概述 Socket,套接字就是两台主机之间逻辑连接的端点.TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP协议是应用层协议 ...
- Java IO最详解
初学java,一直搞不懂java里面的io关系,在网上找了很多大多都是给个结构图草草描述也看的不是很懂.而且没有结合到java7 的最新技术,所以自己来整理一下,有错的话请指正,也希望大家提出宝贵意见 ...
- Java IO用法详解
一.java io 概述 1.1 相关概念 Java IO Java IO即Java 输入输出系统.不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这 ...
- Java IO操作详解
在Java编程中,IO(输入输出)是重要的组成部分,Java应用常常需要从外界输入数据或者把数据输出到外界. Java IO的核心用一句话概括:抽象类或接口之中的抽象方法会根据实例化子类的不同,会完成 ...
- 【java IO序列化详解】
唐门崛起 序列化 1.对象序列化和反序列化 2.JDK类库中的序列化API 3.为什么实现了Serializable接口,就可以被序列化 4.serialVersionUID 4.1 serialVe ...
- java io流详解_一文带你看懂JAVA IO流,史上最全面的IO教学啦
一.IO流是什么 惯例引用百科的回答流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操作 ...
- Java 中IO流详解(附实例代码/面试题)
Java I/O流详解 前言 一.I/O流是什么? 二.IO流分类: 1. 流程图: io流对象 2. io流的优缺点: 3. io 流Java中用途有哪些? 三.一些 io 实例 四.面试题: 前言 ...
- JavaIO流详解——Java教案(十)
文章目录 IO流 相关资源 1. File 访问文件和目录 相对路径和绝对路径 创建文件 查看文件列表 获取所有磁盘的根路径 文件过滤器 小结 2. IO流 流的分类 流的概念模型 3. 字节流和字符 ...
- Java - Stream流详解
文章目录 前言 大家好,好久不见了,最近由于实训的影响导致拖更了,在更新这一次估计javaSE基本上就算是完结了,还有一些落下的后面也会补上的,下次见面就是数据结构了 尽情期待吧!那么就让我们步入St ...
- css三种定位都脱离文档流了吗,CSS布局之脱离文档流详解——浮动、绝对定位脱离文档流的区别...
1.代码 (1)示例代码1 CSS布局之脱离文档流详解--浮动.绝对定位脱离文档流的区别 .left { width: 300px; height: 500px; background: red; f ...
最新文章
- NBT-2019-华大发布全球最大人体肠道细菌基因组集研究成果
- 相册权限_苹果手机惊现漏洞?App在未获取相册权限的情况下成功读取照片
- hiho一下第二周 Hihocoder #1014 : Trie树
- 机器学习部分国内牛人
- 分布式机器学习框架:MxNet
- HDU 4535 吉哥系列故事——礼尚往来
- LoadRunner
- 代码版本管理 GitLab介绍
- 2021年低碳科技白皮书
- 【Matplotlib】 标注一些点
- mysql 痛点_2017年五个最常见Linux的痛点,你了解吗?
- Android添加垂直滚动ScrollView 常见问题
- 进程间通信之管道与有名管道
- 项目-字典-更新字典分组
- MySQL之数据库操作
- 支持断点续传的大文件传输协议
- 面试结束后,向面试官要问的问题
- CentOS7—Firefox—截图工具—fireshot插件
- Repeated DNA Sequences
- 发改委印发《关于促进分享经济发展的指导性意见》
热门文章
- 什么是自然语言处理,自然语言处理能做什么,主要有哪些哪点?
- Exception thrown when sending a message with key=‘null‘
- 完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三_zzjlzx-ChinaUnix博客...
- php 菱形问号,python爬虫出现菱形问号乱码的解决方法
- luci开发小插件_luci框架-LUA的一个web框架使用
- BZOJ 4567: [Scoi2016]背单词
- 【leetcode】Reaching Points
- 你的时间都去哪了?(一)数据分析指标
- 1428C ABBB
- 使用DreamweaverMX2004的搜索替换功能提高工作效率。