公司动态
Java基础复习08:File类、字节流、字符流、缓冲流、转换流、序列化、打印流、Commons-io包介绍
目录一、File类与IO流概述1.1 文件路径的写法和相对路径1.2 File类对象的创建1.3 File类常用API1.4 文件搜索1.5 字符集的编码/解码1.6 IO流概述1.7 IO流的分类1.8 IO体系图二、字节流2.1 文件字节输入流(FileInputStream)创建对象与常用API每次读取一个字节int read()每次读取一个字节数组int read(byte[] buffer)一次读完全部字节→避免解码中文输出乱码2.2 文件字节输出流(FileOutputStream)创建对象与常用API追加管道与覆盖管道每次写出一个字节void write()每次写出一个字节数组void write(byte[] buffer)每次写出一个字节数组的一部分write(byte[] buffer,int pos,int len)2.3 文件拷贝2.4 资源释放try-catch-finallyJava中什么是资源化简finally的释放资源三、字符流3.1 文件字符输入流(FileReader)创建对象与常用API每次读取一个字符int read()每次读取一个字符数组int read(char[] buffer])3.2 文件字符输出流(FileWriter)3.3 Properties3.4 总结四、缓冲流4.1 概述与体系图4.2 字节缓冲流4.3 字节缓冲流改进文件拷贝4.4 字符缓冲流4.5 案例:拷贝出师表 并恢复顺序五、字符转换流5.1 体系图与构造器5.2 字符输入转换流5.3 字符输出转换流六、序列化6.1 概述与体系图6.2 序列化(对象字节输出流)6.3 反序列化(对象字节输入流)七、打印流7.1 体系图7.2 PrintStream/PrintWriter7.3 输出语句重定向八、Commons-io包介绍8.1 简介8.2 常用类和方法8.3 Maven坐标一、File类与IO流概述1.1 文件路径的写法和相对路径第一种需要\\转义出\第二种不会跟转义字符冲突第三种可以跨平台绝对路径依赖当前系统的具体盘符信息相对路径可以直接定位到当前工程下 把资源放在工程里 任何一个平台都可以使用这个路径1.2 File类对象的创建File类在java.io.File包下File类的对象代表操作系统的文件/文件夹File类提供了诸如创建文件对象、获取文件信息(大小 修改时间等)、删除文件、创建文件等等API注意:File对象是不能直接读写文件内容的File的对象可以是文件或者文件夹但是Java不像Windows会计算一个文件夹的总大小所以一般Java里文件夹对象.length()没意义 不会返回准确的字节大小如果想获得某个文件夹大小→递归遍历求和1.3 File类常用API获取文件信息public String getAbsolutePath() 返回此File对象的绝对路径名字符串public String getPath() 获取创建文件对象的时候用的路径public String getName() 返回由此File表示的文件或目录的名称public long length() 返回由此File表示的文件的字节大小创建/删除文件遍历文件夹调用者必须是一个目录(文件夹)的File对象dir.listFiles 如果返回值是null 说明:1.dir不是目录 是个文件2.dir不存在 路径错误3.权限不足(Java和Windows对于权限的理解是有偏差的)4.IO异常1.4 文件搜索非规律化递归 流程化的编程思维importjava.io.File;publicclassSearch{publicstaticvoidmain(String[]args){// 传入搜索源 和 要搜索的文件名称searchFile(newFile(D:/),人类星球);}/** * 搜索某个目录下的全部文件/目录 找到目标文件 * * param dir 被搜索的源目录 * param fileName 被搜索的目标文件名称 */publicstaticvoidsearchFile(Filedir,StringfileName){if(dirnull||!dir.isDirectory()){System.out.println(搜索源不是一个文件夹 或者 未找到该文件夹路径);return;}//说明dir是个文件夹 开始找文件 先获取这个文件夹下面的一级目录File[]filesdir.listFiles();// 调用这个方法可能返回null(dir不是文件夹 文件夹路径错误 没有权限)或者[]// 先保证不是null 再保证.length0if(filesnull||files.length0){//当前目录不存在一级文件对象了 不再继续找return;}//走到这 就可以拿到当前目录的 一级文件对象for(Filefile:files){if(file.isFile()){//如果是文件 则判断是不是要找的文件if(file.getName().contains(fileName)){//模糊查询System.out.println(找到了file.getAbsolutePath());//不直接return 因为有可能不止一个目标文件}}elseif(file.isDirectory()){//如果是文件夹 则继续进去递归搜索searchFile(file,fileName);}}}}1.5 字符集的编码/解码编码是调用方法解码是调用构造器编码:字符串.getBytes()解码:new String(字节数组)本身编码的时候是把1个汉字→3个字节解码的时候把2个字节→1个汉字 所以乱码但是英文一直都是一个字节去编码解码 所以没有乱码1.6 IO流概述输入/输出流:读写数据1.7 IO流的分类都是以内存为基准 往内存去 就是输入 就是读入记忆:Reader就是读入 就是Input输入 读入到内存的Writer就是写出 就是Output输出 写出到磁盘的1.8 IO体系图抽象类不能直接new具体使用还是他们的实现子类二、字节流2.1 文件字节输入流(FileInputStream)创建对象与常用API文件字节输入流 把数据按照字节读入内存可以一个一个字节读入 也可以一组一组字节读入每次读取一个字节int read()返回读取到的字节没有字节可读就返回-1循环改进:但是每次读取一个字节 性能较慢 且出现中文字符无法避免乱码问题每次读取一个字节数组int read(byte[] buffer)返回实际读取到了几个字节没有字节可读就返回-1执行完.read() 数组buf里面存放的内容就是 按照当前规则编码之后的三个字节(英文1字节 中文3字节)注意:最后一桶水 可能有上一桶水剩下的数据改进:循环读取 并且确保实际读取多少字节 就解码多少字节但是如果有中文 输出仍然很容易乱码一次读完全部字节→避免解码中文输出乱码其实字节流就始终是不适合读取文本文件的 字符流更合适方式一:还是每次读取一个字节数组 但是把这个字节数组的大小整个文件大小方式2:官方API 按照当前字符集 直接一次性读完这个文件的全部字节到一个字节数组2.2 文件字节输出流(FileOutputStream)创建对象与常用API按字节把内存中的数据写出到磁盘文件目标文件可以不存在 会自动创建(但是读入内存的情况 文件必须要存在)flush():让write的数据生效(因为写数据的时候可能是先在内存中缓存着的此时如果断电 可能write就失败了)追加管道与覆盖管道注意:覆盖的情况 不是等write之后才覆盖 而是这个os2管道一旦new出来 就直接先清空目标文件每次写出一个字节void write()写中文字符 也会乱码(当前是UTF-8 一个中文三个字节 但是write一次只能写出一个字节)每次写出一个字节数组void write(byte[] buffer)总之记住:如果解码和编码规则不一样 中文就会乱码 数字字母不会乱码要避免规则不一致的情况!!这样就不会乱码了编码解码都是默认的UTF-8每次写出一个字节数组的一部分write(byte[] buffer,int pos,int len)如果想要换行:os.write(\r\n.getBytes());// 换行 单独\n可能在Linux下就不适用了不能直接write字符串 只支持int类型或者字节数组getBytes返回的就是编码后的字节数组2.3 文件拷贝总体来看字节流适合做文件(音视频文件 文本文件都可以)的拷贝 因为任何文件都是以二进制(字节)来存储的但是不适合做中文文本文件的读写(容易乱码)参考代码:路径一定要写对 是文件→文件 out的文件可以没有 会自动创建音视频 文本文件 都可以被拷贝2.4 资源释放try-catch-finally问题:解决方法:那就再把上面的编译时异常try catch一下注意非空校验 这样就一定可以顺利释放资源了Java中什么是资源注意:即使出现异常也会做关闭资源操作化简finally的释放资源finally释放资源的代码太繁琐了简化1:简化2:三、字符流3.1 文件字符输入流(FileReader)创建对象与常用API字节流读取中文输出可能会乱码 字符流更合适读取中文输出(按照单个字符读取)每次读取一个字符int read()读取到的是该字符编码后的码值(包括中文字符)返回值是int 没有可读取的就返回-1每次读取一个字符数组int read(char[] buffer])每次读取一个字符数组→内存中返回值是实际读取到的字符数 没有可读取的就返回-1new String(buf, 0, len) 把已经解码好的buf数组从索引0开始 取长度为len的部分 拼接成一个String对象 不再涉及解码操作3.2 文件字符输出流(FileWriter)注意写入一部分的第三个参数表示长度 而不是索引3.3 PropertiesProperties:1.保存内存中Properties集合的键值对数据→磁盘的属性文件 store()2.加载磁盘的属性文件→内存中Properties对象中 load()常用API:store()从内存→磁盘配置文件load()从磁盘配置文件→内存3.4 总结字节流适合做一切文件数据的拷贝比如音视频、文本 但是不适合读取中文内容输出字符流适合读写文本文件字符流会自动处理编码 字节流不会FileReader字符流:read()时自动解码→得到char[]数组new String(char[],offset,len)是在拼接字符串FileInputStream字节流:read()时是在得到字节编码→得到byte[]数组new String(byte[],offset,len,charset)是在手动解码为字符串四、缓冲流4.1 概述与体系图缓冲流提高效率的核心原理:减少频繁的磁盘I/O操作 用内存当中转站批量读写(用内存空间换I/O次数)普通字节/字符流 读一个字节就访问一次磁盘;写一个字节就刷一次磁盘 而磁盘I/O速度远慢于内存 频繁访问就会非常慢缓冲流内部自带一个默认8KB的字节数组缓冲区读取时 一次性从磁盘读一块数据到内存缓冲区程序再从缓冲区逐个取数据 缓冲区空了 才再去磁盘读一批写出时先把数据写到内存缓冲区 缓冲区满了/手动 flush /关闭流时 才一次性刷到磁盘体系图:字节缓冲输入输出流字符缓冲输入输出流4.2 字节缓冲流原始字节输入输出流→缓冲字节输入输出流功能上没有太大的差异 只是提高了效率4.3 字节缓冲流改进文件拷贝对比原始字节流(用is和os) 缓冲字节流(用bis和bos)的速度快了很多最慢的就是原始字节流按照一个一个字节拷贝 缓冲字节流按照数组拷贝是最快的注意:如果buffer数组的大小是1024字节1KB 缓冲流是最快的但是如果设置成8KB原始字节流按照字节数组拷贝速度可能比缓冲流还快(就好像它也有了一个8KB缓冲区)所以建议是使用缓冲流buffer数组设置为1KB参考代码:importjava.io.*;publicclassTestCopy{privatestaticfinalStringSRC_FILED:\\Media\\人类星球\\有字幕\\人类星球03\\人类星球03.mp4;privatestaticfinalStringDEST_FILED:\\Temp\\;publicstaticvoidmain(String[]args){copy01();}privatestaticvoidcopy01(){longstartTimeSystem.currentTimeMillis();try(InputStreamisnewFileInputStream(SRC_FILE);BufferedInputStreambisnewBufferedInputStream(is);OutputStreamosnewFileOutputStream(DEST_FILEcopy03.mp4);BufferedOutputStreambosnewBufferedOutputStream(os);){byte[]buffernewbyte[1024];intlen0;while((lenbis.read(buffer))!-1){bos.write(buffer,0,len);}}catch(IOExceptione){e.printStackTrace();}longendTimeSystem.currentTimeMillis();System.out.println(复制文件耗时(endTime-startTime)/1000.0s);}}4.4 字符缓冲流字符缓冲输入流多了一个本类特有的方法:按照一行一行来读数据readLine()字符缓冲输入流:把磁盘数据读取到→内存(程序)中字符缓冲输出流多了一个本类特有的方法:写出数据的时候换行newLine()字符缓冲输出流:把内存(程序)中数据输出到→磁盘数据注意:下图红字写错了错误是 “原始流写到内存” 原始流的最终目标是磁盘文件 而非内存4.5 案例:拷贝出师表 并恢复顺序文件数据→读取到内存→在内存排好序→拷贝到目标文件下图只有1~9 自定义比较规则很简单 可以直接用charAt取到序号拓展:如果序号不止一位数 比如11 10→正则表达式来写比较规则参考代码:importjava.io.*;importjava.util.ArrayList;importjava.util.Collections;importjava.util.Comparator;importjava.util.List;importjava.util.regex.Matcher;importjava.util.regex.Pattern;publicclasstest{publicstaticvoidmain(String[]args){try(//读入到内存BufferedReaderbrnewBufferedReader(newFileReader(io-app2/src/csb.txt));//写出到目标文件BufferedWriterbwnewBufferedWriter(newFileWriter(io-app2/src/newcsb1.txt));){ListStringlistnewArrayList();//读取到数据 先暂存到内存 准备排序Stringstr ;while((strbr.readLine())!null){list.add(str);}PatternpatternPattern.compile(^\\d);Collections.sort(list,newComparatorString(){Overridepublicintcompare(Strings1,Strings2){intagetNum(s1);intbgetNum(s2);returnInteger.compare(a,b);}privateintgetNum(Strings){Matchermpattern.matcher(s);returnm.find()?Integer.parseInt(m.group()):0;}});for(Strings:list){bw.write(s);bw.newLine();}}catch(Exceptione){e.printStackTrace();}}}五、字符转换流5.1 体系图与构造器代码编码和文件编码不一致→乱码真正读取文件的功能还是红色完成的绿色只是一个功能拓展(缓冲区) → 装饰者设计模式5.2 字符输入转换流先提取文件的原始字节输入流→按照需要的编码→字符输入流如果使用这个构造器 还是可能乱码:文件是GBK 则指定按照GBK的规则把字节流→字符流就不乱码:1.FileInputStream is new FileInputStream(…) 从文件中原样读取原始字节 不做任何编码/解码 字节内容对应文件的GBK存储格式2.new InputStreamReader(is, “GBK”) 按照GBK编码规则 把读取到的GBK字节流 解码为字符流(不乱码) 若不指定编码 默认UTF-8(会乱码)3.new BufferedReader(isr) 包装字符流 通过缓冲区提升读取效率4.br.readLine() 从缓冲区读取已解码的字符行5.3 字符输出转换流把内存的数据按照某种编码规则写出去六、序列化6.1 概述与体系图对象序列化→对象永久保存→把内存的对象存储到磁盘注意:1.要序列化某个对象 该对象必须实现Serializable序列化接口2.transient修饰的成员变量不参与序列化3.序列化的版本号 与 反序列化的版本号必须一致(serialVersionUID)4.序列化之后的对象 不是给人看的(看似乱码 实际不是乱码) 只是把这个对象信息永久保存了 下次可能要拿到这个对象6.2 序列化(对象字节输出流)把内存中的对象→磁盘中永久保存6.3 反序列化(对象字节输入流)磁盘文件中的对象数据→内存中的Java对象七、打印流7.1 体系图一种更方便 更高效(内部也基于缓冲流)的写数据到磁盘中的流可以实现打印什么就是什么 所见即所得(97→97 a→a true→true)7.2 PrintStream/PrintWriterPrintStream:PrintWriter:代码案例:追加数据要在原始管道加上true7.3 输出语句重定向其实sout就是用的打印流 默认打印到控制台System.setOut(ps)→用自己的打印流八、Commons-io包介绍8.1 简介commons-io是apache开源基金组织提供的一组有关IO操作的类库 可以提高IO功能开发的效率commons-io工具包提供了很多有关io操作的类(常用IOUtils FileUtils)8.2 常用类和方法FileUtils8.3 Maven坐标!-- Commons IO 最新稳定版 --dependencygroupIdcommons-io/groupIdartifactIdcommons-io/artifactIdversion2.16.1/version/dependency