一、IO流是什么

惯例引用百科的回答

流是一种抽象概念,它代表了数据的无结构化传递。按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列。从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出 [1] .

我对IO流的理解就是"你的程序和系统之间读写文件的操作就是IO操作,和系统之间读写用的东西就是IO流"。

JAVA IO流就是JAVA程序和操作系统之间通信用的方法。

二、JAVA IO系统脑图

给大家看下JAVA IO的脑图

自己画的JAVA的脑图,如果有需要原文件的去我公众号,发送:JAVA IO,就可以得到脑图的原文件了,带黄色文件夹标注的是我自己写的注释嗷。

什么你还不知道我公众号,微信搜索,千珏,是千珏(jue)就可以关注到我了。
可以看下我别的文章2019数据分析师必备资源

三、JAVA IO流详解

在这里由于篇幅的原因我只讲解JAVA IO流中的字节流和字符流,别的就等以后再写,比如:NIO AIO BIO这些,以后有时间抽出时间出来写一篇,要是想看的记得点个关注哦。

下面进入正题:

3.1 字节流和字符流的区别

字节流和字符流操作的本质区别只有一个:字节流是原生的操作,字符流是经过处理后的操作。

画个图,字节流在操作时不会用到缓冲区,也就是不会用到内存,文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件,看下图:

为什么要有字符流而不直接用字节流呢?

我相信有些读者心里肯定要问这个问题,我刚开始学习的时候也想过这个问题,为什么不直接用字节流解决呢,还非要搞个字符流出来呢。

我的理解就是字节流处理多个字节表示的东西的时候有可能会出现乱码的问题,比如汉字,用字节流读取的时候有可能因为一位字节没有读到就变成了乱码,字符流呢就完美解决了这个问题,字符流你们可以这样理解,字节流和编码表的组合就是字符流。因为有了编码表所以可以确定这个汉字有多少个字节,这样字节流就可以根据位数准确的读写汉字了。

以上纯为个人理解,如有不对的地方请在评论区给我留言哦。

3.2 字节流

字节流顾名思义就是通过字节直接操作字符,更底层一些。

字节流最基础的两个类就是 InputStreamOutputStream ,根据这两个派生而来类都含有 read()write() 的基本方法,用于读写单个字节或者字节数组。

3.2.1 InputStream 和 OutputStream类

InputStream类是一个抽象类 ,是所有字节输入流类的父类。

OutputStream类是一个抽象类,是所有字节输出流的父类

InputStream的常见子类有:

  • FileInputStream:看这个名字就知道用于从文件中读取信息。
  • ByteArrayInputStream: 字节数组输入流,
  • ObjectInputStream:序列化时使用 一般和ObjectOutputStream一起使用
  • FilterInputStream: 过滤输入流,为基础的输入流提供一些额外的操作。

OutputStream的常见子类有:

  • FileOutPutStream: 文件输出流对文件进行操作
  • ByteArrayOutputStream: 字节数组输出流
  • ObjectOutputStream: 序列化时使用 一般和OjbectInputStream一起使用
  • FilterOutputStream:过滤输出流,为基础的输出流提供一些额外的操作。

我们一个一个过要不然怎么能叫一文带你看懂JAVA IO流了呢,那样不就是标题党了吗[滑稽]。

3.2.1.1 FileInputStream 和 FileOutPutStream类
1) FileInputStream 和 FileOutPutStream概念

FileInputStream是文件字节输入流,就是对文件数据以字节的方式来处理,如音乐、视频、图片等。

FileOutPutStream是文件字节输出流,

2)FileInputStream里面的方法
//通过文件的名字来创建一个对象
public FileInputStream(String name) throws FileNotFoundException{}
//通过File对象来创建一个对象
public FileInputStream(File file) throws FileNotFoundException{}/*** 通过FileDescriptor来创建一个对象* FileDescriptor是一个文件描述符号* 有in,out,err三种类型* in:标准输入描述符,out:标准输出的描述符,err:标准错误输出的描述号*/
public FileInputStream(FileDescriptor fdObj){}
//打开指定的文件进行读取 ,是java和c之间进行操作的api 我们并不会用到
private native void open0(String name){}
//打开指定的文件进行读取,我们并不会用到 因为在构造方法里面帮我们打开了这个文件
private void open(String name){}
//从输入流中读取一个字节的数据,如果到达文件的末尾则返回-1
public int read() throws IOException{}
//读取一个字节数组
private native int readBytes(byte b[], int off, int len) throws IOException;
private native int read0() throws IOException;
//从输入流中读取b.length的数据到b中
public int read(byte b[]) throws IOException{}
//从输入流中读取off到len之间的数据到b中
public int read(byte b[], int off, int len) throws IOException{}
//跳过并丢弃输入流中的n个数据
public long skip(long n) throws IOException{}
private native long skip0(long n) throws IOException;
//可以从此输入流中读取的剩余字节数
public int available() throws IOException {}
private native int available0() throws IOException;
//关闭此文件输入流并释放与该流关联的所有系统资源
public void close() throws IOException {}
//返回FileDescriptor对象
public final FileDescriptor getFD() throws IOException{}
//该方法返回与此文件输入流关联的通道 NIO中会用到 本文不会提及
public FileChannel getChannel(){}
private static native void initIDs();
private native void close0() throws IOException;
//没有更多引用时,调用此方法来关闭输入流 一般不使用
protected void finalize() throws IOException {}

由于篇幅起见FileOutputStream代码里面的方法我就不仔细的带你们看了(我不会说我是因为懒才不带你们看的,溜。

一般常用的方法就几个,举个例子,往D盘下面hello.txt里面输入“hello world”

public class Test {public static void main(String []args) throws IOException {//根据文件夹的名字来创建对象FileOutputStream fileOutputStream = new FileOutputStream("D:\\hello.txt");//往文件里面一个字节一个字节的写入数据fileOutputStream.write((int)'h');fileOutputStream.write((int)'e');fileOutputStream.write((int)'l');fileOutputStream.write((int)'l');fileOutputStream.write((int)'o');String s = " world";//入文件里面一个字节数组的写入文件fileOutputStream.write(s.getBytes());fileOutputStream.close();//传文件夹的名字来创建对象FileInputStream fileInputStream = new FileInputStream("D:\\hello.txt");int by = 0;//一个字节一个字节的读出数据while((by = fileInputStream.read()) != -1){System.out.println((char)by);}//关闭流fileInputStream.close();//通过File对象来创建对象fileInputStream = new FileInputStream("new File("D:\\hello.txt")");byte []bytes = new byte[10];//一个字节数组的读出数据while ((by = fileInputStream.read(bytes)) != -1){for(int i = 0; i< by ; i++){System.out.print((char) bytes[i]);}}//关闭流fileInputStream.close();}
}

常用的就上述代码里面的三种方法。

3.2.1.2 ByteArrayInputStream和ByteArrayOutputStream
1)ByteArrayInputStream和ByteArrayOutputStream概念

ByteArrayInputStream是字节数组输入流,它里面包含一个内部的缓冲区(就是一个字节数组 ),该缓冲区含有从流中读取的字节。

ByteArrayOutputStream是字节数组输出流

2)ByteArrayInputStream里面的方法
//通过byte数组来创建对象
public ByteArrayInputStream(byte buf[]) {}
//通过byte数组,并给定开始下标和结束下标来创建对象
public ByteArrayInputStream(byte buf[], int offset, int length){}
//从这个输入流读取下一个字节 末尾会返回
public synchronized int read(){}
//从输入流中读取off到len之间的数据到b中
public synchronized int read(byte b[], int off, int len){}
//跳过并丢弃输入流中的n个数据
public synchronized long skip(long n){}
//可以从此输入流中读取的剩余字节数
public synchronized int available(){}
//判断这个输入流是否支持标记,他一直返回true
public boolean markSupported(){}
//将mark的值设置为当前读取的下标,readAheadLimit这个参数没有意义,因为没用到
public void mark(int readAheadLimit){}
//将当前的下标设置为mark一般和mark()方法一起使用
public synchronized void reset(){}
//关闭这个输入流,因为ByteArrayInputStream操作的是数组所以没有必要关闭流
public void close() throws IOException{}

由于篇幅起见ByteArrayOutputStream代码里面的方法我就不仔细的带你们看了(我不会说我是因为懒才不带你们看的,溜

举个例子,从一个字符串读取数组

public class Test {public static void main(String[] args) throws IOException {//创建一个字节输出流对象ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();//一个字节一个字节的写入数据byteArrayOutputStream.write('h');byteArrayOutputStream.write('e');byteArrayOutputStream.write('l');byteArrayOutputStream.write('l');byteArrayOutputStream.write('o');//一个字节数组的写入数据byteArrayOutputStream.write(" world".getBytes());ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray();//从这个流中读取数据int b = 0;//从这个流中一个字节一个字节的读数据while ((b = byteArrayInputStream.read()) != -1) {System.out.println((char) b);}byteArrayInputStream = new ByteArrayInputStream(bytes);byte[] bs = new byte[10];//从这个流中一次性读取bs.length的数据while ((b = byteArrayInputStream.read(bs)) != -1) {for (int i = 0; i < b; i++) {System.out.print((char) bs[i]);}System.out.println();}}
}

如上代码所示,我平时常用的也就这几个方法。

3.2.1.3 ObjectInputStream 和ObjectOutpuStream
1)概念

ObjectInputStream是反序列化流,一般和ObjectOutputStream配合使用。

用ObjectOutputStream将java对象序列化然后存入文件中,然后用ObjectInputStream读取出来

这个类的作用,我的理解是有些类在这个程序生命周期结束后,还会被用到所以要序列化保存起来

2)ObjectInputStream 和 ObjectOutpuStream 基本方法

常用的其实就两个方法

public final Object readObject(){}
public final void writeObject(Object obj) throws IOException{}
 class Data implements Serializable {private int n;public Data(int n){this.n=n;}@Overridepublic String toString(){return Integer.toString(n);}
}
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {Data w=new Data(2);ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("worm.out"));//序列化对象,把对象写到worm.out里面out.writeObject("Worm storage\n");//序列化对象,把对象写到worm.out里面out.writeObject(w);out.close();//从worm.out里面读取对象 ObjectInputStream in=new ObjectInputStream(new FileInputStream("worm.out"));//读取String对象String s=(String)in.readObject();//读取Data对象Data d=(Data)in.readObject();System.out.println(s+"Data = "+d);}
}
3.2.1.4 FilterInputStream 和 FilterOutputStream
1) 概念

FilterInputStream和FilteOutputStream分别是过滤输入流和过滤输出流,他们的作用是为基础流提供一些额外的功能

2)FilterInputStream 和 FilterOutputStream的常用子类

FilterInputStream常用子类

  • DataInputStream:可以从流中读取基本数据类型,与DataOutpuStream配合一起使用
  • BufferedInputStream:可以从缓冲区中读取数据,不用每次和文件的操作都进行实际操作了。

FilterOutputStream常用子类

  • DataOutputStream:可以向文件中写入基本类型的数据
  • PrintStream:用于产生格式化的输出
  • BufferedOutputStream:通过缓冲区像文件中写入数据。

DataInputStream基本类型写入方法。

// 将一个 byte 值写入流中。
void writeByte(int v)
// 将一个 short 值写入流中
void writeShort(int v)
//将一个 int 值写入流中
void writeInt(int v)
// 将一个 long 值写入流中
void writeLong(long v)
//使用 Float 类中的 floatToIntBits 方法将 float 参数转换为一个 int 值,然后该int值写入流中
void writeFloat(float v)
//使用Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,然后将该long写入到流中。
void writeDouble(double v)
//写入一个char
void writeChar(int v)
//将一个 boolean 值写入流。
void writeBoolean(boolean v)
//将字节数组写入流中
void write(byte[] b, int off, int len) //将字符串写出到基础输出流中。
oid writeBytes(String s)
//采用UTF-16be方式写入,也就是java字符串的编码
void writeChars(String s)
// 以utf-8形式写入一个字符串
void writeUTF(String str)
//清空此数据输出流,写入文件
void flush()

测试一下方法试试

public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("D:\\hello.txt"));// 写入byte类型数据dataOutputStream.writeByte(20);// 写入short类型数据dataOutputStream.writeShort(30);// 写入int类型dataOutputStream.writeInt(900);// 写入float类型dataOutputStream.writeFloat(12.3f);// 写入long类型dataOutputStream.writeLong(800L);// 写入double类型dataOutputStream.writeDouble(14.23);//写入boolean类型dataOutputStream.writeBoolean(true);// 写入char类型dataOutputStream.writeChar('中');dataOutputStream.close();DataInputStream dataInputStream = new DataInputStream(new FileInputStream("D:\\hello.txt"));System.out.println(dataInputStream.readByte());System.out.println(dataInputStream.readShort());System.out.println(dataInputStream.readInt());System.out.println(dataInputStream.readFloat());System.out.println(dataInputStream.readLong());System.out.println(dataInputStream.readDouble());System.out.println(dataInputStream.readBoolean());System.out.println(dataInputStream.readChar());dataInputStream.close();//创建一个对象PrintStream printStream = new PrintStream("D:\\hello.txt");//写入一个字节数组printStream.write("helloworld".getBytes());//写入一个换行符号printStream.println();//格式化写入数据printStream.format("文件名称:%s","hello.txt");printStream.println();printStream.append("abcde" );printStream.close();}
}

BufferedInputStream和BufferedOutputStream我另开一篇文章写,里面要介绍的东西很多,一篇文章介绍不完。

emmm,还有字符流下篇文章写,今天是完不成了,觉得这篇文章还可以想看下一篇文章的关注我呀,或者可以关注我公众号:千珏呀,后台留言给我呀,是千珏(jue),不是千钰。

3.3 字符流

3.3.1 Reader类和Writer类

字符流:就是在字节流的基础上,加上编码,形成的数据流

字符流出现的意义:因为字节流在操作字符时,可能会有中文导致的乱码,所以由字节流引申出了字符流。

字符流最基础的两个类就是 Readerwirter,根据这两个派生而来类都含有read()write()` 的基本方法。

处理图片、视频、音乐的时候还是用字节流吧,处理文本文件的时候用字符流会好很多。

Reader类常见子类有:

  • FileReader:文件输入流
  • BufferedReader: 带缓冲区的字符输入流

Writer类常见子类有:

  • FileWriter:文件输出流
  • BufferedWriter:带缓冲区的字符输出流

3.3.1.1 FileReader类和FileWriter类

直接看实例吧

public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {FileWriter fileWriter = new FileWriter("D:\\hello.txt");//向文件里面写入文件fileWriter.write("123");//向文件里面写入文件,和writer的区别就是append返回的是FileWriter对象,而write没有返回值fileWriter.append("hello world");fileWriter.append("中");//把流中的数据刷新到文件中,还能继续使用// 如果没有刷新,也没有关闭流的话 数据是不会写入文件的fileWriter.flush();//关闭流fileWriter.close();FileReader fileReader = new FileReader("D:\\hello.txt");int len = 0;while ((len = fileReader.read()) != -1) {System.out.println((char) len);}//用char数组读数据。char[] chars = new char[1024];while ((len = fileReader.read(chars)) != -1) {System.out.println(chars);}fileReader.close();}
}

FilerWriter 和FileReader 没啥好讲的,具体常用的方法也就上面的,具体使用我也写在注释上面了。

3.3.1.2 BufferedReader类和BufferedWriter类

public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {//从控制台得到输入流BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));//创建文件BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\hello.txt"));String input = null;while(!(input = bufferedReader.readLine()).equals("exit")){//将从控制台得到的数据写入文件bufferedWriter.write(input);//写入一个当前系统下的空行bufferedWriter.newLine();}bufferedWriter.close();bufferedReader.close();}
}

写下面的程序的时候还有一点小插曲,我调用close方法关程序的时候,我调用了两次bufferedReader.close();这就会导致我的文件里面没有数据,痛哭,加了flush发现之后发现文件里面又有数据了,这个时候突然间有个疑问,难道是BufferedWriter的close()方法里面没有调用flush()吗,要自己手动的调用 flush(),淦,那也太蠢了吧,于是去源码里面看了一眼。

public void close() throws IOException {synchronized (lock) {if (out == null) {return;}try (Writer w = out) {flushBuffer();} finally {out = null;cb = null;}}}

源码里面是有flush()操作的呀,为什么我的程序出问题,一顿检查之后 发现文末写了两个bufferedReader的关闭方法,好吧为自己的愚蠢浪费了十分钟的时间QAQ。

四、总结

一般大佬都有总结 ,我也写个总结吧,也算是跟个风。

总的来说这篇文章写的很差,本来想带你们详细看下字节流和字符流的,结果因为年末的时候事情太多,导致我没有办法完成这一事情,只能简略的带你们看看io是怎么用的,并没有看io流为什么能这样用,没有看io流的实现,本质是想一个源码一个一个源码的过一边,一是因为时间不够,二是因为篇幅太长太枯燥,怕你们也看不下去,只能等以后出单章一个类一个类的源码解析看看,如果你们想看的话,给我留言吧。

这次不是太满意 ,希望下篇文章可以写的满意些吧。
各位看官觉得写得还可以的,点个关注吧。

一文带你看懂JAVA IO流,史上最全面的IO教学啦(附送JAVA IO脑图相关推荐

  1. java byte char io流_一文带你看懂JAVA IO流,史上最全面的IO教学

    原标题:一文带你看懂JAVA IO流,史上最全面的IO教学 一.IO流是什么 惯例引用百科的回答 流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符 ...

  2. java io流详解_一文带你看懂JAVA IO流,史上最全面的IO教学啦

    一.IO流是什么 惯例引用百科的回答流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操作 ...

  3. javaio流_一文带你看懂JAVA IO流,史上最全面的IO教学啦

    一.IO流是什么 惯例引用百科的回答 流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操 ...

  4. 一文带你看懂JAVA IO流(一),史上最全面的IO教学啦(附送JAVA IO脑图)

    一.IO流是什么 惯例引用百科的回答 流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操 ...

  5. 一文带你看懂 MySQL 存储引擎

    本文目录: 1.MySQL体系结构 2.存储引擎介绍 3.MySQL 存储引擎特性 4.MySQL 有哪些存储引擎 5.了解 MySQL 数据存储方式 6.MySQL存储引擎介绍 6.1 CSV存储引 ...

  6. 机器学习(1)一文带你看懂显卡,显卡驱动,CUDA,CUDNN(内含举例)

    一文带你看懂显卡,显卡驱动,CUDA,CUDNN(内含举例) 显卡 显卡驱动 CUDA CUDNN 举一个生动形象的例子 显卡 显卡是硬件设备.(花钱购买的) (注:显卡不是GPU,显卡的核心组件包含 ...

  7. [不看后悔啊!]史上最为全面的Autocad施工图视频教程 看完就能成为装修设计师 http://www.51zxw.net/study.asp?vip=1573837

    [不看后悔啊!]史上最为全面的Autocad施工图视频教程 看完就能成为装修设计师 http://www.51zxw.net/study.asp?vip=1573837 沈阳设计:http://hom ...

  8. 一文带你看懂java 泛型,史上最全面的泛型教学啦。

    认真看这篇文章,保证你们对泛型又有新的理解,如果没有的话,请顺着网线来打我呀. 概述 引用下百度百科的回答 泛型是程序设计语言的一种特性.允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那 ...

  9. 一文带你看懂Spring事务!

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 前言 Spring事务管理我相信大家都用得很多,但可能仅仅局限于一个@Transactiona ...

最新文章

  1. 7-6 混合类型数据格式化输入 (C语言)
  2. Java基础:详解static关键字与类加载顺序
  3. leetcode C++ 4. 寻找两个有序数组的中位数 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log
  4. 栏目图片 栏目描述_网站描述怎么写?对网站优化有什么作用?
  5. 从DataTable高效率导出数据到Excel
  6. 嵩天-Python语言程序设计程序题--第二周:基本图形绘制
  7. C# 中对象与JSON字符串相互转换的三种方法
  8. [CSA35G][XSY3318]Counting Quests (DP)
  9. 建设工程项目全寿命周期管理是指_(必过)2020年二建机电《施工管理》考前必背精华知识点整理一...
  10. 使用消息队列的十大理由
  11. Csharp: Searching Within a String
  12. #常见电池型号介绍 常见电池尺寸是多少【详解】
  13. Java | PTA练习:伪随机数题解
  14. Python笔记:数据切片
  15. C++学习(三九二)-fPIC, -fpic, -fpie, -fPIE
  16. Qt pro 文件详解
  17. vue项目搭建和配置
  18. 五十岁:人生的另一种透彻
  19. altera DCFIFO IP核 功能仿真
  20. 玉米价格期货保险(玉米 期货 价格)

热门文章

  1. 《经理人常犯的11种错误》观后感
  2. 计算方法实验(四):牛顿迭代法
  3. 融资数据采集以及分析风险投资数据
  4. 如何根据实际需求选择合适的三维实景建模方式?
  5. 周怎么换算成月_最大的黄金ETF出现增持,震荡周如何操作?
  6. python开源软件排行榜_10大Python开源项目推荐(Github平均star2135)
  7. 用‘+‘替换字符串中的所有空格[复制]
  8. Ubuntu 11.04 更新源(ubuntu yuan)
  9. 微信小程序实战之天气预报
  10. (附源码)springboot工单管理系统 毕业设计 964158