Java IO
Java I/O
IO 4 个抽象类:InputStream、OutputStream、Reader、Writer
InputStream、OutputStream操作字节byte[] 读取,写入。
Reader、Writer 操作字符char[] 读取,写入。
一 字节流
1. InputStream
- int read():读取数据
- int read(byte b[], int off, int len):从第 off 位置开始读,读取 len 长度的字节,然后放入数组 b 中
- long skip(long n):跳过指定个数的字节
- int available():返回可读的字节数
- void close():关闭流,释放资源
FileInputStream类
- 读取字节:read()方法会读取一个字节并返回其整数表示。如果已经到达文件的末尾,则返回 -1。如果在读取时发生错误,则会抛出 IOException 异常。
// 创建一个 FileInputStream 对象 FileInputStream fis = new FileInputStream("test.txt"); // 读取文件内容 int data; while ((data = fis.read()) != -1) { System.out.print((char) data); } // 关闭输入流 fis.close();
- 使用字节数组读取:read(byte[] b) 方法会从输入流中最多读取 b.length 个字节,并将它们存储到缓冲区数组 b 中。
// 创建一个 FileInputStream 对象 FileInputStream fis = new FileInputStream("test.txt"); // 读取文件内容到缓冲区 byte[] buffer = new byte[1024]; int count; while ((count = fis.read(buffer)) != -1) { System.out.println(new String(buffer, 0, count)); } // 关闭输入流 fis.close();
FileOutputStream类
- 如果文件不存在,则创建一个新文件;如果文件已经存在,则覆盖原有文件。
String filename = "example.txt"; FileOutputStream fos = new FileOutputStream(filename, true); // 追加模式 String content = "this is content\n"; // 只使用换行符 fos.write(content.getBytes()); fos.close();
- FileOutputStream 写入字节数据
write(int b) write(byte[] b) // 写入字节数组 write(byte[] b,int off,int len) //从`off`索引开始,`len`个字节 写入指定长度字节数组
使用FileOutputStream,FileInputStream 复制文件
public static void copyFile(String source,String dest) throws FileNotFoundException, IOException{ FileInputStream fis = null; FileOutputStream fos = null; try { // 文件输出流,复制文件 fos = new FileOutputStream(dest); // 文件输入流,源文件 fis = new FileInputStream(source); // 创建一个缓冲区数组以存储读取的数据 byte[] buffer = new byte[1024]; int count; // 读取原始图片文件并将数据写入复制后的图片文件 while ((count = fis.read(buffer)) != -1) { fos.write(buffer, 0, count); } fis.read(new byte[1024]); } catch (IOException e) { System.out.print("Exception"); } finally { fos.close(); fis.close(); } }
二 字符流
字符流是一种用于读取和写入字符数据的输入输出流。与字节流不同,字符流以字符为单位读取和写入数据,而不是以字节为单位。常用来处理文本信息。
1. Reader
- int read():读取单个字符
- int read(char cbuf[], int off, int len):从第 off 位置开始读,读取 len 长度的字符,然后放入数组 b 中
- long skip(long n):跳过指定个数的字符
- int ready():是否可以读了
- void close():关闭流,释放资源
FileReader
FileReader构造方法
// 使用File对象创建流对象 File file = new File("a.txt"); FileReader fr = new FileReader(file); // 使用文件名称创建流对象 FileReader fr = new FileReader("b.txt");
FileReader读取字符数据
读取字符:read方法,每次可以读取一个字符,返回读取的字符(转为 int 类型),当读取到文件末尾时,返回-1。代码示例如下:
// 使用文件名称创建流对象 FileReader fr = new FileReader("abc.txt"); // 定义变量,保存数据 int b; // 循环读取 while ((b = fr.read())!=-1) { System.out.println((char)b); } // 关闭资源 fr.close();
读取指定长度的字符:read(char[] cbuf, int off, int len),并将其存储到字符数组中。其中,cbuf 表示存储读取结果的字符数组,off 表示存储结果的起始位置,len 表示要读取的字符数。代码示例如下:
File textFile = new File("docs/约定.md"); // 给一个 FileReader 的示例 // try-with-resources FileReader try(FileReader reader = new FileReader(textFile);) { // read(char[] cbuf) char[] buffer = new char[1024]; int len; while ((len = reader.read(buffer, 0, buffer.length)) != -1) { System.out.print(new String(buffer, 0, len)); } }
2. Writer
- void write(int c): 写入一个字符
- void write( char cbuf[], int off, int len): 将数组 cbuf 中的从 off 位置开始,长度为 len 的字符写入
- void flush(): 强制刷新,将缓冲区的数据写入
- void close():关闭流
FileWriter
FileWriter 构造方法
// 第一种:使用File对象创建流对象 File file = new File("a.txt"); FileWriter fw = new FileWriter(file); // 第二种:使用文件名称创建流对象 FileWriter fw = new FileWriter("b.txt");
写入字符
try (FileWriter fw = new FileWriter("b.txt", true)) { // 写入字符:write(int b) 方法,每次可以写出一个字符,代码示例如下: fw.write(72); // 写入字符'H'的ASCII码 fw.write(101); // 写入字符'e'的ASCII码 fw.write(108); // 写入字符'l'的ASCII码 fw.write(108); // 写入字符'l'的ASCII码 fw.write(111); // 写入字符'o'的ASCII码 // 写入字符数组:write(char[] cbuf) 方法,将指定字符数组写入输出流。代码示例如下: char[] chars = { 'c', 'h', 'a', 'r', '[', ']' }; fw.write(chars); // 将字符数组写入文件 // 写入指定字符数组:write(char[] cbuf, int off, int len) 方法,将指定字符数组的一部分写入输出流。代码示例如下: char[] chars1 = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; fw.write(chars1, 0, 5); // 将字符数组的前 5 个字符写入文件 // 写入字符串:write(String str) 方法,将指定字符串写入输出流。代码示例如下: String str = "write String"; fw.write(str); // 将字符串写入文件 fw.write("hello\r\n".toCharArray()); // 追加 fw.append("jinnan"); // 刷新缓冲区,流对象可以继续使用 fw.flush(); // 先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了 fw.close(); }
因为 FileWriter 内置了缓冲区 ByteBuffer,所以如果不关闭输出流,就无法把字符写入到文件中。
如果我们既想写入数据,又想继续使用流,就需要 flush 方法了。
三 字节缓冲流
Java 的缓冲流是对字节流和字符流的一种封装,通过在内存中开辟缓冲区来提高 I/O 操作的效率。Java 通过 BufferedInputStream 和 BufferedOutputStream 来实现字节流的缓冲,通过 BufferedReader 和 BufferedWriter 来实现字符流的缓冲。
缓冲流的工作原理是将数据先写入缓冲区中,当缓冲区满时再一次性写入文件或输出流,或者当缓冲区为空时一次性从文件或输入流中读取一定量的数据。这样可以减少系统的 I/O 操作次数,提高系统的 I/O 效率,从而提高程序的运行效率。
BufferedInputStream & BufferedOutputStream
构造:
// 创建字节缓冲输入流,先声明字节流 FileInputStream fps = new FileInputStream(b.txt); BufferedInputStream bis = new BufferedInputStream(fps) // 创建字节缓冲输入流(一步到位) BufferedInputStream bis = new BufferedInputStream(new FileInputStream("b.txt")); // 创建字节缓冲输出流(一步到位) BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
读取
//从该输入流中读取一个字节 public int read(); //从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。 public int read(byte[] b,int off,int len);
输出
//向输出流中输出一个字节 public void write(int b); //将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。 public void write(byte[] b,int off,int len); //刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中。 public void flush();
byte 类型通常被用于存储二进制数据,例如读取和写入文件、网络传输等场景。在这些场景下,byte 类型的变量可以用来存储数据流中的每个字节,从而进行读取和写入操作。
使用:
BufferedInputStream bis =null; BufferedOutputStream bos = null; try{ bis = new BufferedInputStream(new FileInputStream("test.jpg")); bos= new BufferedOutputStream(new FileOutputStream("copytest3.jpg")); //缓冲区的空间有 8 个 1024 字节 byte[] bytes = new byte[8*1024]; int data; while ((data = bis.read(bytes)) != -1) { bos.write(bytes, 0 , data); } }finally{ bis.close(); bos.close(); }
四 字符缓冲流
BufferedReader & BufferedWriter
构造
// 创建字符缓冲输入流 BufferedReader br = new BufferedReader(new FileReader("b.txt")); // 创建字符缓冲输出流 BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
- BufferedReader:String readLine(): 读一行数据,读取到最后返回 null
- BufferedWriter:newLine(): 换行,由系统定义换行符。
//readLine // 创建流对象 BufferedReader br = new BufferedReader(new FileReader("a.txt")); // 定义字符串,保存读取的一行文字 String line = null; // 循环读取,读取到最后返回null while ((line = br.readLine())!=null) { System.out.print(line); System.out.println("------"); } // 释放资源 br.close(); //newLine() // 创建流对象 BfferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); // 写出数据 bw.write("周杰伦"); // 写出换行 bw.newLine(); bw.write("陈奕迅"); bw.newLine(); bw.write("李宗盛"); bw.newLine(); bw.write("五月天"); bw.newLine(); // 释放资源 bw.close();
五 转换流
转换流可以将一个字节流包装成字符流,或者将一个字符流包装成字节流。这种转换通常用于处理文本数据,如读取文本文件或将数据从网络传输到应用程序。
编码与解码:
String str = "test String"; // 编码 byte[] bytes = str.getBytes("utf8"); System.out.println("编码: "+bytes); // 解码 String newStr = new String(bytes,"utf8"); System.out.println("解码: "+newStr);
1. InputStreamReader
将字节流(InputStream)转换为字符流(Reader),同时支持指定的字符集编码方式,从而实现字符流与字节流之间的转换
构造:
InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt")); InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
InputStreamReader 类的常用方法包括:
- read():从输入流中读取一个字符的数据。
- read(char[] cbuf, int off, int len):从输入流中读取 len 个字符的数据到指定的字符数组 cbuf 中,从 off 位置开始存放。
- ready():返回此流是否已准备好读取。
- close():关闭输入流。
2. OutputStreamWriter
将字符流转换为字节流,是字符流到字节流的桥梁。
构造:
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("a.txt")); OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("b.txt") , "GBK");
OutputStreamWriter 类的常用方法包括:
- write(int c):向输出流中写入一个字符的数据。
- write(char[] cbuf, int off, int len):向输出流中写入指定字符数组 cbuf 中的 len 个字符,从 off 位置开始。
- flush():将缓冲区的数据写入输出流中。
- close():关闭输出流。
在使用转换流时,需要指定正确的字符集编码方式,否则可能会导致数据读取或写入出现乱码。
总结:
六 拓展 File
File对象既可以表示文件,也可以表示目录。
File构造方法:
public static void main(String[] args) throws FileNotFoundException, IOException { //创建一个文件对象, File f = new File("test.txt"); f.createNewFile(); // 创建文件 //字节写入流 FileOutputStream fos = new FileOutputStream(f); fos.write("你好".getBytes("utf8")); System.out.print( "create file: " + f.getName() + "\n" + "getPath: " + f.getPath() + "\n" + "getParent: " + f.getParent() + "\n" + "AbsolutePath: " + f.getAbsolutePath() + "\n" + "canRead: " + f.canRead() + "\n" + "length: " + f.length() + "\n" + "isDirectory: " + f.isDirectory()+"\n" + "isFile: " + f.isFile()+"\n" + "exists: " + f.exists()); }
Apache FileUtils 类
//复制文件或目录 File srcFile = new File("path/to/src/file"); File destFile = new File("path/to/dest/file"); // 复制文件 FileUtils.copyFile(srcFile, destFile); // 复制目录 FileUtils.copyDirectory(srcFile, destFile); File file = new File("path/to/file"); // 删除文件或目录 FileUtils.delete(file); File srcFile = new File("path/to/src/file"); File destFile = new File("path/to/dest/file"); // 移动文件或目录 FileUtils.moveFile(srcFile, destFile); File srcFile = new File("path/to/src/file"); File destFile = new File("path/to/dest/file"); // 移动文件或目录 FileUtils.moveFile(srcFile, destFile);
Hutool FileUtil 类
//copyFile:复制文件。该方法可以将指定的源文件复制到指定的目标文件中。 File dest = FileUtil.file("FileUtilDemo2.java"); FileUtil.copyFile(file, dest); //move:移动文件或目录。该方法可以将指定的源文件或目录移动到指定的目标文件或目录中。 FileUtil.move(file, dest, true); //del:删除文件或目录。该方法可以删除指定的文件或目录,如果指定的文件或目录不存在,则会抛出异常。 FileUtil.del(file); //rename:重命名文件或目录。该方法可以将指定的文件或目录重命名为指定的新名称。 FileUtil.rename(file, "FileUtilDemo3.java", true); //readLines:从文件中读取每一行数据。 FileUtil.readLines(file, "UTF-8").forEach(System.out::println);
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战