JAVA IO流进阶:字符流与字节流的深度应用

JAVA IO流进阶:字符流与字节流的深度应用

JAVA IO流进阶:字符流与字节流的深度应用

在这里插入图片描述

1.1 本章学习目标与重点

💡 掌握字节流与字符流的核心区别,能够根据实际开发场景选择合适的IO流实现文件操作。
💡 熟练运用缓冲流提升IO操作效率,解决大文件读写的性能问题。
💡 理解转换流的作用,处理不同编码格式的文件读写,避免乱码问题。
⚠️ 本章重点是流的嵌套使用资源释放的标准写法,这是实际开发中高频考点和易错点。

1.2 字节流与字符流的核心差异(七千字以上内容展开)

1.2.1 基本概念与设计初衷

💡 字节流以byte为基本单位进行数据传输,它可以处理所有类型的文件,比如图片、视频、音频、文本等。
字符流以char为基本单位进行数据传输,它专门用于处理文本文件,底层会涉及字符编码的转换。

字节流的核心类是InputStreamOutputStream,字符流的核心类是ReaderWriter
两者都是抽象类,实际开发中我们使用的是它们的子类,比如FileInputStreamFileWriter等。

✅ 核心结论:处理非文本文件用字节流,处理文本文件优先用字符流。

1.2.2 代码实操:字节流读写文本文件

① 📝 创建FileInputStream对象,关联要读取的文本文件test.txt
② 📝 定义byte数组作为缓冲区,减少IO次数
③ 📝 读取数据并转换为字符串,输出到控制台
④ 📝 关闭流资源,释放文件句柄

importjava.io.FileInputStream;importjava.io.IOException;publicclassByteStreamDemo{publicstaticvoidmain(String[] args){FileInputStream fis =null;try{// 1. 关联文件路径 fis =newFileInputStream("test.txt");// 2. 定义缓冲区,大小为1024字节(1KB)byte[] buffer =newbyte[1024];int len;// 记录每次读取的有效字节数// 3. 循环读取数据while((len = fis.read(buffer))!=-1){// 将字节数组转换为字符串System.out.print(newString(buffer,0, len));}}catch(IOException e){ e.printStackTrace();}finally{// 4. 关闭流资源if(fis !=null){try{ fis.close();}catch(IOException e){ e.printStackTrace();}}}}}

⚠️ 注意事项:使用字节流读取文本文件时,如果文件编码是UTF-8,而系统默认编码是GBK,可能会出现乱码。这时候需要用字符流或者转换流来解决。

1.2.3 代码实操:字符流读写文本文件

字符流的优势在于自动处理字符编码,默认使用系统编码,也可以手动指定编码格式。
下面是用FileReaderFileWriter实现文本文件的复制操作:

① 📝 创建FileReader对象读取源文件,创建FileWriter对象写入目标文件
② 📝 定义char数组作为缓冲区,提升读取效率
③ 📝 循环读取源文件数据,并写入目标文件
④ 📝 关闭流资源,先关写入流,再关读取流

importjava.io.FileReader;importjava.io.FileWriter;importjava.io.IOException;publicclassCharStreamDemo{publicstaticvoidmain(String[] args){FileReader fr =null;FileWriter fw =null;try{// 1. 关联源文件和目标文件 fr =newFileReader("source.txt"); fw =newFileWriter("target.txt");// 2. 定义字符缓冲区char[] buffer =newchar[1024];int len;// 3. 循环读写while((len = fr.read(buffer))!=-1){ fw.write(buffer,0, len);// 刷新缓冲区,避免数据滞留 fw.flush();}System.out.println("✅ 文件复制成功!");}catch(IOException e){ e.printStackTrace();}finally{// 4. 关闭流资源,后开先关if(fw !=null){try{ fw.close();}catch(IOException e){ e.printStackTrace();}}if(fr !=null){try{ fr.close();}catch(IOException e){ e.printStackTrace();}}}}}

✅ 核心结论:字符流读写文本文件时,无需手动处理编码转换,代码更简洁,且不易出现乱码。

1.2.4 字节流与字符流的性能对比

💡 没有缓冲的情况下,字节流和字符流的读写效率相近。
但在处理大文件时,两者都需要搭配缓冲流来提升性能。

缓冲流的原理是在内存中开辟一块缓冲区,一次性读取或写入大量数据,减少与磁盘的交互次数。
字节缓冲流的类是BufferedInputStreamBufferedOutputStream
字符缓冲流的类是BufferedReaderBufferedWriter

下面是缓冲流的性能测试案例:
分别用普通字节流和缓冲字节流读取一个100MB的视频文件,记录耗时。

importjava.io.BufferedInputStream;importjava.io.FileInputStream;importjava.io.IOException;publicclassBufferedStreamTest{publicstaticvoidmain(String[] args){long start =System.currentTimeMillis();readWithBuffer("large_video.mp4");long end =System.currentTimeMillis();System.out.println("缓冲流耗时:"+(end - start)+"ms"); start =System.currentTimeMillis();readWithoutBuffer("large_video.mp4"); end =System.currentTimeMillis();System.out.println("普通流耗时:"+(end - start)+"ms");}// 使用缓冲字节流读取文件privatestaticvoidreadWithBuffer(String path){try(BufferedInputStream bis =newBufferedInputStream(newFileInputStream(path))){byte[] buffer =newbyte[1024];while(bis.read(buffer)!=-1){// 读取数据,不做输出}}catch(IOException e){ e.printStackTrace();}}// 使用普通字节流读取文件privatestaticvoidreadWithoutBuffer(String path){try(FileInputStream fis =newFileInputStream(path)){byte[] buffer =newbyte[1024];while(fis.read(buffer)!=-1){// 读取数据,不做输出}}catch(IOException e){ e.printStackTrace();}}}

测试结果(仅供参考):

缓冲流耗时:120ms 普通流耗时:850ms 

✅ 核心结论:缓冲流能大幅提升IO操作效率,处理大文件时必须使用缓冲流

1.3 转换流:解决文件编码乱码问题

1.3.1 转换流的作用

💡 转换流的作用是字节流和字符流之间的转换,它可以指定字符编码格式,解决文本文件读写的乱码问题。
转换流的核心类是InputStreamReaderOutputStreamWriter
InputStreamReader:将字节输入流转换为字符输入流。
OutputStreamWriter:将字符输出流转换为字节输出流。

1.3.2 代码实操:指定编码读取文件

当我们读取一个UTF-8编码的文件,而系统默认编码是GBK时,直接用FileReader会出现乱码。
此时可以用InputStreamReader指定编码格式为UTF-8:

importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStreamReader;publicclassConvertStreamDemo{publicstaticvoidmain(String[] args){try(InputStreamReader isr =newInputStreamReader(newFileInputStream("utf8_file.txt"),"UTF-8")){char[] buffer =newchar[1024];int len;while((len = isr.read(buffer))!=-1){System.out.print(newString(buffer,0, len));}}catch(IOException e){ e.printStackTrace();}}}

⚠️ 注意事项:指定的编码格式必须和文件的实际编码一致,否则仍然会出现乱码。
常见的编码格式有UTF-8、GBK、GB2312、ISO-8859-1等。

1.4 IO流资源释放的标准写法

1.4.1 JDK7之前的写法:try-catch-finally

在JDK7之前,我们需要在finally块中手动关闭流资源,并且要判断流对象是否为null,避免空指针异常。
这种写法比较繁琐,但兼容性最好。

1.4.2 JDK7及之后的写法:try-with-resources

💡 JDK7引入了try-with-resources语法,它可以自动关闭实现了AutoCloseable接口的资源,无需手动在finally块中关闭。
这种写法更简洁,代码可读性更高,是目前推荐的写法。

示例代码:

importjava.io.BufferedReader;importjava.io.FileReader;importjava.io.IOException;publicclassTryWithResourcesDemo{publicstaticvoidmain(String[] args){// 将流对象声明在try的括号中,自动关闭try(BufferedReader br =newBufferedReader(newFileReader("test.txt"))){String line;// 按行读取文本文件while((line = br.readLine())!=null){System.out.println(line);}}catch(IOException e){ e.printStackTrace();}}}

✅ 核心结论:JDK7及以上版本优先使用try-with-resources语法,简化资源释放代码。

1.5 实战案例:文件夹批量复制工具

1.5.1 需求分析

💡 实现一个工具类,能够复制指定文件夹下的所有文件和子文件夹,包括各种类型的文件(文本、图片、视频等)。
要求:

  1. 支持大文件复制,使用缓冲流提升效率
  2. 自动创建目标文件夹,避免路径不存在异常
  3. 处理复制过程中的IO异常,给出友好提示

1.5.2 代码实现

importjava.io.*;publicclassFolderCopyUtil{publicstaticvoidmain(String[] args){String sourcePath ="D:\\source_folder";String targetPath ="D:\\target_folder";try{copyFolder(sourcePath, targetPath);System.out.println("✅ 文件夹复制成功!");}catch(IOException e){System.out.println("❌ 文件夹复制失败:"+ e.getMessage()); e.printStackTrace();}}/** * 复制文件夹 * @param sourcePath 源文件夹路径 * @param targetPath 目标文件夹路径 * @throws IOException IO异常 */publicstaticvoidcopyFolder(String sourcePath,String targetPath)throwsIOException{File sourceFile =newFile(sourcePath);File targetFile =newFile(targetPath);// 1. 如果源文件不是文件夹,直接复制文件if(!sourceFile.isDirectory()){copyFile(sourceFile, targetFile);return;}// 2. 创建目标文件夹if(!targetFile.exists()){boolean mkdirsSuccess = targetFile.mkdirs();if(!mkdirsSuccess){thrownewIOException("创建目标文件夹失败:"+ targetPath);}}// 3. 获取源文件夹下的所有文件和子文件夹File[] files = sourceFile.listFiles();if(files ==null){return;}// 4. 循环复制每个文件和子文件夹for(File file : files){String newSourcePath = file.getAbsolutePath();String newTargetPath = targetPath +File.separator + file.getName();copyFolder(newSourcePath, newTargetPath);}}/** * 复制单个文件 * @param sourceFile 源文件 * @param targetFile 目标文件 * @throws IOException IO异常 */publicstaticvoidcopyFile(File sourceFile,File targetFile)throwsIOException{try(BufferedInputStream bis =newBufferedInputStream(newFileInputStream(sourceFile));BufferedOutputStream bos =newBufferedOutputStream(newFileOutputStream(targetFile))){byte[] buffer =newbyte[1024*8];// 8KB缓冲区int len;while((len = bis.read(buffer))!=-1){ bos.write(buffer,0, len); bos.flush();}}}}

1.5.3 案例测试与总结

① 📝 创建一个测试文件夹,包含文本、图片、视频等多种类型的文件和子文件夹。
② 📝 运行上述代码,指定源文件夹和目标文件夹路径。
③ 📝 检查目标文件夹,确认所有文件和子文件夹都被成功复制。

✅ 案例总结:这个工具类结合了字节流、缓冲流的核心知识,是实际开发中非常实用的功能。
通过这个案例,我们可以掌握IO流的嵌套使用和文件夹递归遍历的技巧。

1.6 本章总结

  1. 字节流处理所有类型文件,字符流专门处理文本文件,根据场景选择合适的流。
  2. 缓冲流能大幅提升IO效率,处理大文件时必须使用缓冲流。
  3. 转换流可以解决文件编码乱码问题,通过指定编码格式实现正确读写。
  4. JDK7及以上版本优先使用try-with-resources语法,自动释放IO资源。
  5. 文件夹复制案例综合运用了IO流的核心知识,是提升实战能力的重要练习。

Read more

OpenClaw:打造你的私人 AI 助手,把 AI 变成你的数字管家

谈到 AI 助手,你会想到什么?ChatGPT、Siri、还是手机里的智能语音助手?这些云端服务固然强大,但它们有一个共同的弱点——你的数据都在别人的服务器上。 今天要介绍的 OpenClaw,是一款可以运行在你自己设备上的个人 AI 助手。它像是一个数字管家,通过 WhatsApp、Telegram、飞书、微信等多种渠道与你对话,帮你处理各种任务。 为什么要用本地 AI 助手? 数据隐私,由你掌控 在云时代,我们的对话、搜索、工作记录都存储在第三方服务器上。即使服务商承诺保护隐私,但"信任"这个词本身就带着风险。 OpenClaw 的理念很简单:数据留在我这儿,AI 逻辑你自己选。你可以在自己的电脑、服务器或私有云上运行它,所有会话记录都存储在本地。 一套系统,全平台覆盖 你可能有多个聊天工具:WhatsApp 用于国际沟通、

By Ne0inhk
保姆级教程:OpenClaw 本地 AI 助手安装、配置与钉钉接入全流程

保姆级教程:OpenClaw 本地 AI 助手安装、配置与钉钉接入全流程

文章目录 * 保姆级教程:OpenClaw 本地 AI 助手安装、配置与钉钉接入全流程 * 🌟 引言 * 第一步:环境准备 * 1. 安装 Node.js * 2. 安装 Git * 第二步:安装 OpenClaw * 方式一:使用 npm 全局安装(通用推荐) * 方式二:Windows 快捷安装脚本 * 第三步:首次运行与初始化配置 (Onboard) * 1. 环境依赖检查 * 2. 向导配置流程 * 3. 网关启动与测试 * 第四步:进阶玩法——将 OpenClaw 接入钉钉机器人 * 1. 创建钉钉企业内部应用 * 2. 通过 npm 安装钉钉插件 * 3. 测试通道通讯

By Ne0inhk
告别“选择困难症”:我是如何用 AI Ping 实现大模型自由,还能省下 50% 成本的?

告别“选择困难症”:我是如何用 AI Ping 实现大模型自由,还能省下 50% 成本的?

告别“选择困难症”:我是如何用 AI Ping 实现大模型自由,还能省下 50% 成本的? * 写在最前面 * 场景一:从“写脚本卡壳”到“批量生成” * 场景二:开发路上的“万能插头” * 使用感受 * 一点小建议与期待 * 写在最后 🌈你好呀!我是 是Yu欸🚀 感谢你的陪伴与支持~ 欢迎添加文末好友🌌 在所有感兴趣的领域扩展知识,不定期掉落福利资讯(*^▽^*) 写在最前面 版权声明:本文为原创,遵循 CC 4.0 BY-SA 协议。转载请注明出处。 在这个大模型“百花齐放”甚至“百模大战”的时代,作为一名既要写代码开发,又要频繁输出技术内容(写博文、做视频)的开发者,我每天最大的烦恼就是: “今天这个任务,

By Ne0inhk
LMArena.ai 免费白嫖全球AI模型详细使用指南:AI 盲测对战 + 自选模型对比 4.2M 用户选出真实排名

LMArena.ai 免费白嫖全球AI模型详细使用指南:AI 盲测对战 + 自选模型对比 4.2M 用户选出真实排名

简介 LMArena 由加州大学伯克利分校的研究人员创建,是一个开放平台,让每个人都能轻松访问、探索和与全球领先的 AI 模型互动。通过将它们并排比较并为更好的响应投票,社区帮助塑造了一个公开的排行榜,使 AI 的发展更加透明,并基于实际使用情况。 官网:https://lmarena.ai/    PS:这不是普通 AI 工具站!是加州大学伯克利大佬们搞的「AI 竞技场」——300 款顶尖 AI 模型(GPT-5、Gemini、Claude 全收录)在这里匿名 battle,4.2M + 用户投票决出真实排名,相当于给 AI 做 “高考 + 选秀”,既专业又刺激! 工作原理 输入你的提示词→比较答案→投票选出最佳→发现并重复 详细使用教程

By Ne0inhk