以后开发中会遇到文件的上传和下载,都是需要用到IO流
咱们电脑上面所有的文件, 文档 音频 图片 视频 等都是可以进行读和写的。他们咋读的?
咋写的? 一下子就写到咱们项目中了吗?不是,依靠流的形式进行读 和写。很抽象
在读取的时候,会将咱们的文件(音频 视频 等)变成流的形式 一点一点来处理的 拆解开来出来的。
1.1缓冲的概念
看视频有点卡?暂停一下,加载缓冲一下。
快递:送到物流中转站,然后分批次的发。物流中转站就是缓冲的概念。
IO流 的本质就是对电脑的文件进行读和写的
计算机通过CPU内存读取磁盘上面的文件数据,一次读取1字节。但是可以加上缓冲的概念
每次读取4kb。效率会高点的,咱们可以测试一下。效率是不是确实高了。
1.2IO流的分类
咱们今天的学习紧紧围绕着:
1.从磁盘读取数据到内存(Java代码) 磁盘=》代码中 输入流
2.从内存(Java代码 String str = "狗蛋很帅")写入数据到磁盘某一个文件 代码=》磁盘 输出流
参照物:是内存,就是Java代码。
输入流: 从磁盘读取到内存
输出流:从内存写入到磁盘
I:
input: 输入 从磁盘读取数据到内存
使用input输入流的应用场景是啥:比如 磁盘上面有一个1.txt文件,将1.txt文件的内容读取到Java内存中。使用的是输入流。
输入流分为两种:
1.字节输入流 FileInputStream
2.字符输入流
输出流分为两种:
1.字节输出流 FileOutputStream
2.字符输出流
1.2.1字节输入流
讲一个新的知识点,你最起码先知道这个知识点能干嘛?
字节输入流:磁盘上面有一个1.txt文件,现在要将1.txt文件中的内容读取到内存(Java代码中)
Java给咱们封装好了类: FileInputStream 文件输入流(字节输入流)
package com.qfedu.a_fileinputstream; import java.io.*; public class Demo1 { public static void main(String[] args) throws IOException { //将磁盘上面的c:/aaa/1.txt文件这个数据读取到内存(Java)中 //加上缓冲的效果,这种很牛逼啊,将磁盘上面的东西弄到咱们Java代码中 //1.创建File对象,是咱们本地磁盘文件的一个File对象 //为啥要创建这个File对象?因为要读取1.txt这个文件的里面的 //内容,首先先找到文件再说啊。 File file = new File("c:/aaa/1.txt"); //2.创建文件字节输入流对象,来操作1.txt //FileInputStream(File file) //通过打开与实际文件的连接创建一个 FileInputStream , // 该文件由文件系统中的 File对象 file命名。 //将c:/aaa/1.txt文件转为字节输入流的形式,之后可以按照流的形式读取到内存中 FileInputStream fis = new FileInputStream(file); //3.fileInputStream 这个流不具备缓冲的效果。 //但是加上缓冲的效果!!! 咋办?使用另外一个流 //BufferedInputStream //A BufferedInputStream为另一个输入流添加了功能,即缓冲输入 //咋加?将FileInputStream传给BufferedInputStream 此时 //FileInputStream 就具备缓冲的功能了!!! BufferedInputStream bis = new BufferedInputStream(fis); //使用字节缓冲流操作咱们的1.txt //当创建BufferedInputStream时, // 将创建一个内部缓冲区数组,这个数组是什么数据类型的? //5.创建一个缓冲区的数组 byte 为啥是byte类型的数组 //因为是字节输入流 所以是byte byte 就是字节 //当缓冲数组是2个字节的时候,每次读取的时候存到缓冲数组中,只存2个字节 //发现数据一次性读取不完?咋办?咋解决? byte[] buf = new byte[1024 * 4];//缓冲区4096字节 //现在数组是空的 //6.读取数据 //public int read(byte[] b) // throws IOException //从输入流读取一些字节数,并将它们存储到缓冲区b 。 // 实际读取的字节数作为整数返回 //将1.txt文件的内容 读取到缓冲数组中 buf 里面 //之前buf是一个空的数组,现在通过read方法将1.txt文件中的 //内容读取到了 buf空的数组中 // int read = bis.read(buf); // System.out.println(read); //6.调用read方法之后,buf 数组就有值了 能不能打印一下 //借助于String类来展示byte数组的内容 //buf 给字符串 为了展示字节数组中的内容的 //0 偏移量 buf这个数组中从哪开始取值 从下标为0 的地方取值 //read 取6个 //如果b的长度为零,则不会读取字节并返回0 ; // 否则,尝试读取至少一个字节。 // 如果没有字节可用,因为流在文件末尾,则返回值-1 int length = -1; //如果length=-1 那么就会到达流的末尾 就证明后面没哟数据 //循环结束,不要再读了 while ((length = bis.read(buf)) != -1) { //循环4次 System.out.println("狗蛋"); //数组中的东西要展示出来 使用String //将磁盘上面的内容 读取到 =》 内存 buf System.out.println(new String(buf, 0, length)); } //7.流是需要关闭的 bis.close(); fis.close(); } }
知道字节输入流是干嘛的?可以将磁盘上面的某一个文件读取到Java代码中(内存)
固定的写法!!!但是你得知道每行代码是啥意思
package com.qfedu.a_fileinputstream; import java.io.*; public class Demo2 { public static void main(String[] args) throws IOException { //1.创建File对象 File file = new File("c:/aaa/7.txt"); //2.创建字节输入流,将7.txt扔给 fis对象了 FileInputStream fis = new FileInputStream(file); //3.创建字节缓冲流, fis又扔给 bis了 现在咱们的数据在bis里面了 BufferedInputStream bis = new BufferedInputStream(fis); //4.声明一个缓冲数组,将bis里面的数据读取出来 赋值给这个 //缓冲数组 byte[] buf = new byte[4 * 1024];//4096字节 //5.开始使用read方法进行读取,读取的时候使用while循环 //如果7.tx文件中的字节数超过了4096个字节,需要使用循环,再次的读取 int length; //现在数据都在bis里面,咱们要把bis里面的数据读取buf这个数组中 while ((length = bis.read(buf)) != -1) { //byte数组有值以后,咱们可以打印一下看看byte数组中的数据 System.out.println("循环执行"); //将字节数组转为字符串,的目的是为了看一下字节数组中的数据 //并没有实际的意义 System.out.println(new String(buf, 0, length)); } //6.关闭流 bis.close(); fis.close(); } }
案例:读取你们盘符下面的一个txt文档,打印在idea控制台。写完以后,将代码直接发到扣扣群里
好好想想这个流程是咋走的?
想象咱们班门口放了一袋大米(就是磁盘的本地文件,文件的内容),现在我要求把门口给我运到我的讲台(Java的内存),不能使用袋子直接搬运?
你们咋解决?可以找一个杯子(就是缓冲数组)。一杯子一杯子的运。能接受不?
比如磁盘上面的380字节的数据, 咋把读取到内存中? 弄一个缓冲数组,每次读取3字节
BufferedInputStream 其实FileInputStream其实一次读取一个字节的,但是使用BufferedInputStream 了之后,可以搞一个缓冲的数组,一次可以读取多个,那么循环次数就会减少,代码的效率就会提升。循环1000遍 和循环1遍的效率 循环1遍的效率,下午演示 加缓冲流和不加缓冲流哪个效率高。
abcdefg 每次读取3个字节 第一次 abc while (length = 3 != -1) { true sout(abc) } 第二次 def while (length = 3 != -1) {true sout(def) } 第三次 while ((length = 1)!= -1 ) {true sout(g)new String(buf, 0, 1) } 当到达文件的末尾的时候, 后面没有东西了,文件的末尾了,到达流的末尾了。返回值是-1 while ((length = -1) != -1) { false 循环结束 sout(abc) }
1.2.2字节输出流
将Java中数据写入到磁盘上面
内存-》磁盘 输出流
讲什么案例? 比如Java代码中有一个字符串 String str = "唉,愁人";将这个字符串写入磁盘某一个文件中
FileOutputStream
package com.qfedu.b_fileoutstream; import java.io.*; public class Demo1 { public static void main(String[] args) throws IOException { //将Java代码中的一个字符串写入到咱们的磁盘的某一个文件中 //1.创建File对象,文件路径对象 告知编译器要把数据写到哪个文件中 File file = new File("c:/aaa/2.txt"); //2.实例化字节输出流对象 FileOutputStream fos = new FileOutputStream(file); //3.对FileOutputStream 加上缓冲的效果 //猜测一下 FileInputStream所对应的缓冲流 BufferedInputStream //FileOutputStream 所对应的缓冲流 BufferedOutputStream BufferedOutputStream bos = new BufferedOutputStream(fos); //4.将一个字符串写入到磁盘中 String str = "大家再等我一天,后天见面!!!"; // write(byte[] b) //咱们的参数是字节数组,咋办?str是一个字符串 但是参数是一个字节数组,咋解决? //str是字符串 不能强转 将字符串转为字节数组,没有讲过!!! //将str字符串转为字节数组 byte[] bytes = str.getBytes(); bos.write(bytes); //5.写完以后一定要刷新流然后关闭流 bos.flush();//没有实际的意义,可以不写的 //6.关闭流 //在输入流的时候一定是先开的后关,后开的先关 bos.close(); fos.close(); } }
package com.qfedu.b_fileoutstream; import java.io.*; public class Demo2 { public static void main(String[] args) throws IOException { //将内容写入到3.txt文件中 File file = new File("c:/aaa/3.txt"); FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos); //开始写了 //void write(int b); //传参是一个int类型,但是真正写入的时候是int类型所对应的字符 bos.write(97);//开发不用!!! bos.flush(); bos.close(); fos.close(); } }
package com.qfedu.b_fileoutstream; import java.io.*; public class Demo3 { public static void main(String[] args) throws IOException { File file= new File("c:/aaa/4.txt"); FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos); String str = "abcdefg";//7个字节 //write(byte[] b,int off,int len) byte[] bytes = str.getBytes(); //写一个到缓冲流 从0开始偏移 写入2个字节 //可以借助于循环往里面写!!! bos.write(bytes, 0, 2);//ab bos.write(bytes, 2, 2);//cd bos.write(bytes, 4, 2);//ef bos.write(bytes, 6, 1);//ef bos.flush(); bos.close(); fos.close(); } }
package com.qfedu.b_fileoutstream; import java.io.*; public class Demo4 { public static void main(String[] args) throws IOException { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("c:/aaa/4.txt"))); bos.write("xixida".getBytes()); bos.flush(); bos.close(); } }
针对于咱们的讲的字节输入流和字节输出流来一个案例
将c:/bbb文件夹下面一个视频 (源文件) 复制到c:/aaa文件夹下面
思路:将bbb文件夹下面的视频先读取到内存,然后再从内存写入磁盘aaa文件夹下面
缓冲数组 byte[] buf = new byte[4]; 视频由字节组成的 一次读取 4096字节 直到最后一次 不一定4096字节 最后一次3456 字节 write(buf, 0, 3456) 相当与将所有字节重新拼接了一下 读取的时候每次读取4096个放到咱们的缓冲数组中,然后立马写入另外磁盘文件下面 直到读取完,写入完即可 qwertyuiopasd 13字节 //第一循环 while ((length=bis.read(buf)) != -1) {//buf 里面 有 qwer bos.write(buf, 0, 4); 文本里面有 qwer } 第二次循环 while ((length=bis.read(buf)) != -1) {//buf 里面 有 tyui bos.write(buf, 0, 4); 文本里面有 qwertyui } 第三次循环 while ((length=bis.read(buf)) != -1) {//buf 里面 有 opas bos.write(buf, 0, 4); 文本里面有 qwertyuiopas } 第四次循环 while ((length=bis.read(buf)) != -1) {//buf 里面 有 d bos.write(buf, 0, 1); 文本里面有 qwertyuiopasd }
package com.qfedu.c_io; import java.io.*; public class Demo1 { public static void main(String[] args) throws IOException { copyVideo1(); } //现在咱们讲的这个是带有缓冲的,看看带有缓冲视频的复制的耗时多少 2610ms //写一个方法将bbb文件夹下面的3.map4格式的视频复制到aaa文件夹下面 //用带缓冲的,效率高 public static void copyVideo () throws IOException { //获取系统的当前的毫秒数 long start = System.currentTimeMillis(); //1.创建字节缓冲输入流 将磁盘的数据读取到内存 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("c:/bbb/3.mp4"))); //2.创建字节缓冲输出流 从内存写入到的文件 源文件是mp4格式,写入到的也必须是mp4格式的 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("c:/aaa/goudan.mp4"))); //3.准备一个字节数组 缓冲区数组 byte[] buf = new byte[4 * 1024];//代码走到这一步是空的 //4.从磁盘读取数据到内存 int length = -1; //这个视频很大,依靠循环来读取,每次读4 * 1024字节 while ((length = bis.read(buf)) != -1) {//从磁盘上读取数据到buf缓冲数组中 //每次循环 buf数组中有值,顺便依靠循环写入到磁盘 System.out.println("qwer"); bos.write(buf, 0, length); } //5.关闭流 bos.close(); bis.close(); //复制完以后再得到一个毫秒数,相减 就得到复制一个视频需要的时间 long end = System.currentTimeMillis(); System.out.println(end - start); } //下面来=看一下不带缓冲的流的读写 public static void copyVideo1 () throws IOException { long start = System.currentTimeMillis(); FileInputStream fis = new FileInputStream(new File("c:/bbb/3.mp4")); FileOutputStream fos = new FileOutputStream(new File("c:/aaa/goudan.mp4")); int length = -1; while ((length = fis.read()) != -1) { fos.write(length); } fos.close(); fis.close(); long end = System.currentTimeMillis(); System.out.println(end - start); } }
1.2.3字符输入流【非重点】
也是输入流,将磁盘的某一个文件读取到内存
FileReader:
是一个阅读字符文件的便利类,是专门处理字符文件的,比如txt文件。音频视频图片
不能使用这个流。
是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
牵涉到解码,底层是字节流,但是会解码为字符。如果解码失败就意味着咱们读取失败了
一般不会使用字符流操作图片 音频 视频等,因为牵涉到解码。会出问题!!!
开发一般使用字节流!!!
package com.qfedu.d_FileReader; import java.io.*; public class Demo1 { public static void main(String[] args) throws IOException { //将c盘下面的aaa文件夹下面的1.txt文件的内容 读取到Java内存中 //和字节流一模一样 //1.新建一个File对象 File file = new File("c:/aaa/1.txt"); //2.新建FileReader 对象 字符输入流 FileReader fr = new FileReader(file); //3.FileRFeader没有缓冲的效果,可以加上缓冲的效果 //杂加?BufferedReader BufferedReader br = new BufferedReader(fr); //4.字节的缓冲数组 是字节 //字符的缓冲数组 是字符 char[] cbuf = new char[4];//缓冲区是4个字符 //这个方法是用的!!! //5. read(char[] cbuf) 将文件内容读取到字符数组中(缓冲区) int length = -1; while ((length = br.read(cbuf)) != -1) { System.out.println(length); //6.将数组展示到控制台 System.out.println(new String(cbuf, 0, length)); } //7.关闭流 br.close(); fr.close(); } }
package com.qfedu.d_FileReader; import java.io.*; public class Demo2 { public static void main(String[] args) throws IOException { //将c盘下面的aaa文件夹下面的1.txt文件的内容 读取到Java内存中 //和字节流一模一样 //1.新建一个File对象 File file = new File("c:/aaa/1.txt"); //2.新建FileReader 对象 字符输入流 FileReader fr = new FileReader(file); //3.FileRFeader没有缓冲的效果,可以加上缓冲的效果 //杂加?BufferedReader BufferedReader br = new BufferedReader(fr); //这个方法不用!!! //5.int read() 一次读取一个字符,返回值是字符对应的assic码值 int length = -1; while ((length = br.read()) != -1) { System.out.println(length); } //7.关闭流 br.close(); fr.close(); } }
package com.qfedu.d_FileReader; import java.io.*; public class Demo3 { public static void main(String[] args) throws IOException { //将c盘下面的aaa文件夹下面的1.txt文件的内容 读取到Java内存中 //和字节流一模一样 //1.新建一个File对象 File file = new File("c:/aaa/1.txt"); //2.新建FileReader 对象 字符输入流 FileReader fr = new FileReader(file); //3.FileRFeader没有缓冲的效果,可以加上缓冲的效果 //杂加?BufferedReader BufferedReader br = new BufferedReader(fr); //4.字节的缓冲数组 是字节 //字符的缓冲数组 是字符 char[] cbuf = new char[4];//缓冲区是4个字符 //这个也不用!!! //5. read(char[] cbuf, 0, length) 将文件内容读取到字符数组中(缓冲区) int length = -1; while ((length = br.read(cbuf, 0, 2)) != -1) { System.out.println(length); //6.将数组展示到控制台 System.out.println(new String(cbuf, 0, length)); } //7.关闭流 br.close(); fr.close(); } }
package com.qfedu.d_FileReader; import java.io.*; public class Demo4 { public static void main(String[] args) throws IOException { //将c盘下面的aaa文件夹下面的1.txt文件的内容 读取到Java内存中 //和字节流一模一样 //1.新建一个File对象 File file = new File("c:/aaa/1.txt"); //2.新建FileReader 对象 字符输入流 FileReader fr = new FileReader(file); //3.FileRFeader没有缓冲的效果,可以加上缓冲的效果 //杂加?BufferedReader BufferedReader br = new BufferedReader(fr); //一次读取一行数据,r如果到达行的末尾就返回就是一个null // String s = br.readLine(); // System.out.println(s); // String s1 = br.readLine(); // System.out.println(s1); String str; //有可能会用的 while ((str = br.readLine()) != null) { System.out.println(str); } //7.关闭流 br.close(); fr.close(); } }
1.2.4z字符输出流
案例:
将一个字符串类型的数据写入到磁盘中
FileWriter
写字符文件一个便利类
package com.qfedu.e_fileWriter; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; public class Demo1 { public static void main(String[] args) throws IOException { //从内存写入数据到磁盘的文件中 File file = new File("c:/aaa/2.txt"); FileWriter fw = new FileWriter(file); //加缓冲流 BufferedWriter bw = new BufferedWriter(fw); //viod writer(char[] cbuf, int off, int length); String str = "今天的天气真的太热了"; //将字符串转为char数组 char[] chars = str.toCharArray(); //将chars数组中 从0 开始 取3个字符写入到缓冲流中 bw.write(chars, 3, 3); bw.close(); fw.close(); } }
package com.qfedu.e_fileWriter; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; public class Demo2 { public static void main(String[] args) throws IOException { //从内存写入数据到磁盘的文件中 File file = new File("c:/aaa/2.txt"); FileWriter fw = new FileWriter(file); //加缓冲流 BufferedWriter bw = new BufferedWriter(fw); //viod writer(char[] cbuf); String str = "今天的天气真的太热了"; //将字符串转为char数组 char[] chars = str.toCharArray(); //将chars数组中,直接将字符数组中的所有的数据写到缓冲流中 bw.write(chars); bw.close(); fw.close(); } }
package com.qfedu.e_fileWriter; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; public class Demo3 { public static void main(String[] args) throws IOException { //从内存写入数据到磁盘的文件中 File file = new File("c:/aaa/2.txt"); FileWriter fw = new FileWriter(file); //加缓冲流 BufferedWriter bw = new BufferedWriter(fw); //viod writer(String str); String str = "对方网络不佳!!!"; //viod writer(String str, int off, int length); //bw.write(str); //bw.write(str, 1, 4); bw.write("呵呵"); bw.newLine();//写完呵呵以后换行写 功能代码 起到一个换行的作用 bw.write("哈哈"); bw.newLine(); bw.write("嘻嘻"); bw.close(); fw.close(); } }
综合案例:
复制一本小说到另外一个盘符下面
package com.qfedu.e_fileWriter; import java.io.*; public class Demo4 { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader(new File("c:/bbb/DiBa.txt"))); BufferedWriter bw = new BufferedWriter(new FileWriter(new File("c:/aaa/sb1.txt"))); int length = -1; char[] cbuf = new char[4 * 1024]; while ((length = br.read(cbuf)) != -1) { bw.write(cbuf, 0, length); } bw.close(); br.close(); } }