1. IO流的分类 > 流向的不同:输入流、输出流 > 处理单位的不同:字节流、字符流 > 流的角色的不同:节点流、处理流 2. 基础IO流的框架: 抽象基类 4个节点流 (也称为文件流) InputStream FileInputStream OutputStream FileOutputStream Reader FileReader Writer FileWriter 说明:本章虽然涉及到的流很多,但是使用流进行数据的读写操作是非常标准和规范的。 3. FileReader \ FileWriter 的使用 3.1 执行步骤: 第1步:创建读取或写出的File类的对象 第2步:创建输入流或输出流 第3步:具体的读入或写出的过程。 读入:read(char[] cbuffer) 写出:write(String str) / write(char[] cbuffer,0,len) 第4步:关闭流资源,避免内存泄漏 3.2 注意点: ① 因为涉及到流资源的关闭操作,所以出现异常的话,需要使用try-catch-finally的方式来处理异常 ② 对于输入流来讲,要求File类的对象对应的物理磁盘上的文件必须存在。否则,会报FileNotFoundException 对于输出流来讲,File类的对象对应的物理磁盘上的文件可以不存在。 > 如果此文件不存在,则在输出的过程中,会自动创建此文件,并写出数据到此文件中。 > 如果此文件存在,使用 FileWriter(File file) 或 FileWriter(File file,false): 输出数据过程中,会新建同名的文件对现有的文件进行覆盖。 FileWriter(File file,true) : 输出数据过程中,会在现有的文件的末尾追加写出内容。 4. FileInputStream \ FileOutputStream 的使用 4.1 执行步骤: 第1步:创建读取或写出的File类的对象 第2步:创建输入流或输出流 第3步:具体的读入或写出的过程。 读入:read(byte[] buffer) 写出:write(byte[] buffer,0,len) 第4步:关闭流资源,避免内存泄漏 4.2 注意点: > 在3.2 注意点的基础之上,看其他的注意点。 > 对于字符流,只能用来操作文本文件,不能用来处理非文本文件的。 对于字节流,通常是用来处理非文本文件的。但是,如果涉及到文本文件的复制操作,也可以使用字节流。 说明: 文本文件:.txt 、.java 、.c、.cpp、.py等 非文本文件:.doc、.xls 、.jpg 、.pdf、.mp3、.mp4、.avi 等 查看FileReader的API
FileReader是间接继承于Reader
所以可以用Reader的方法
int read() :每次读取一个字符 返回是Int类型的
读取一个字符 也就是二个字节
package src.com.atguigu02.filestream; import org.junit.Test; import java.io.File; import java.io.FileReader; import java.io.IOException; /** * ClassName: FileReaderWriterTest * Package: src.com.atguigu02.filestream * Description: * * @Author 小白 * @Create 2024/4/14 14:59 * @Version 1.0 */ public class FileReaderWriterTest { /* * 需求:读取hello.txt中的内容,显示在控制台上。 * * 异常使用throws的方式处理,不太合适。见 test2() * */ /*java.io.FileReader `类用于读取字符文件,构造时使用系统默认的字符编码和默认字节缓冲区。 - `FileReader(File file)`: 创建一个新的 FileReader ,给定要读取的File对象。 - `FileReader(String fileName)`: 创建一个新的 FileReader ,给定要读取的文件的名称。 */ @Test public void test1() throws IOException { //1.创建File类的对象,对应着hello.txt文件 File file = new File("hello.txt"); //2.创建输入型的字符流对象,用于读取数据 FileReader fr = new FileReader(file); //3.读取数据,并显示在控制台上 //方式1 // int data =fr.read(); //先读一个 然后进行判断 // while (data !=-1){ //然后判断是不是等于-1 如果等于 就不在读 // System.out.println((char) data); // data = fr.read(); // } //方式2 //data过来 先让fr去reaad 去读一下(helloworld123)第一个文件的第一个"h"是不是 =-1 如果不是输出打印 在返回 int data; while ((data = fr.read()) != -1) { System.out.print((char) data); } //4. 流资源的关闭操作(必须要关闭,否则会内存泄漏) fr.close(); } /* * 需求:读取hello.txt中的内容,显示在控制台上。 * 使用try-catch-finally的方式处理异常。确保流一定可以关闭,避免内存泄漏 * */ @Test public void test2() { FileReader fr = null; try { //1.创建File类的对象,对应着hello.txt文件 File file = new File("hello.txt"); //2.创建输入型的字符流,用于读取数据 fr = new FileReader(file); //3.读取数据,并显示在控制台上 int data; while ((data = fr.read()) != -1) { System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } finally { //4. 流资源的关闭操作(必须要关闭,否则会内存泄漏) try { if (fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
升级版本
int read(char[ ] cbuf)
每次读取一个字符 就去和磁盘交互 效果太差 所以我们先放在char[ ] 数组里面 在去和磁盘进行交互 效果会好一点 好比快递小哥送快递 要去拿个小车去送 才能送得多
/* * 需求:读取hello.txt中的内容,显示在控制台上。 * * 对test2()进行优化,每次读取多个字符存放到字符数组中,减少了与磁盘交互的次数,提升效率。 * * */ @Test public void test3() { FileReader fr = null; try { //1.创建File类的对象,对应着hello.txt文件 File file = new File("hello.txt"); //2.创建输入型的字符流,用于读取数据 fr = new FileReader(file); //3.读取数据,并显示在控制台上 char[] cbuffer = new char[5]; int len; while ((len = fr.read(cbuffer)) != -1) { //遍历数组:错误的写法 // for (int i = 0; i < cbuffer.length; i++) { // System.out.print(cbuffer[i]); // } //遍历数组:错误的写法 for (int i = 0; i < len; i++) { System.out.print(cbuffer[i]); } } } catch (IOException e) { e.printStackTrace(); } finally { //4. 流资源的关闭操作(必须要关闭,否则会内存泄漏) try { if (fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } } }
读的话 文件要有 而且要有内容读
写 (可以没有 然后去写) 输出流
/* * 需求:将内存中的数据写出到指定的文件中 * */ @Test public void test4() { FileWriter fw = null; try { //1. 创建File类的对象,指明要写出的文件的名称 File file = new File("info.txt"); //2. 创建输出流 //覆盖文件,使用的构造器: fw = new FileWriter(file); // fw = new FileWriter(file,false); //在现有的文件基础上,追加内容使用的构造器: // fw = new FileWriter(file,true); //3. 写出的具体过程 //输出的方法:write(String str) / write(char[] cdata) fw.write("I love U!\n"); fw.write("You love him!\n"); fw.write("太惨了..."); System.out.println("输出成功"); } catch (IOException e) { e.printStackTrace(); } finally { //4. 关闭资源 try { if (fw != null) fw.close(); } catch (IOException e) { e.printStackTrace(); } } }
读写一起
/* * 需求:复制一份hello.txt文件,命名为hello_copy.txt * */ @Test public void test5() { FileReader fr = null; FileWriter fw = null; try { //1. 创建File类的对象 File srcFile = new File("hello.txt"); File destFile = new File("hello_copy.txt"); //2. 创建输入流、输出流 fr = new FileReader(srcFile); fw = new FileWriter(destFile); //3. 数据的读入和写出的过程 char[] cbuffer = new char[5]; int len;//记录每次读入到cbuffer中的字符的个数 while ((len = fr.read(cbuffer)) != -1) { //write(char[] cbuffer,int fromIndex,int len) fw.write(cbuffer, 0, len); //正确的 // fw.write(cbuffer); //错误的 } System.out.println("复制成功"); } catch (IOException e) { e.printStackTrace(); } finally { //4. 关闭流资源 //方式1: // try { //if (fw != null) // fw.close(); // } catch (IOException e) { // e.printStackTrace(); // }finally { // // try { //if (fr != null) // fr.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } //方式2: try { if (fw != null) fw.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } } }