【Java I/O流 基本问题】记录面试题宝典中自己不熟悉的Java I/O流
创始人
2025-05-31 09:37:50
0

文章目录

  • File类学习
  • 字节流与字符流
  • 缓冲流
  • 转换流
  • 对象流
  • NIO

File类学习

预备知识
1. 文件分隔符
Windows:D:\Soft\QQ\Plugin
Linux:D:/Soft/QQ/Plugin

2. 换行
Windows:换行 = 回车+换行,即\r\n
Linux:换行 = 换行,即\n

3. IDEA默认的当前路径
工程Project的根就是IDEA的默认当前路径

4. IDEA文件分隔符格式
Windows: File file = new File(D:\test\test.txt);
Linux:File file = new File(D://test//test.txt);
统一:File testFile = new File(“D:” + File.separator + “test” + File.separator + fileName);

创建文件

public class FileTest {public static void main(String[] args) throws IOException {// 创建D:\filepath\test\test.txtFile testFile = new File("D:\filepath\test\test.txt");// 获取test.txt文件的上级路径File fileParent = testFile.getParentFile();// 创建多级目录if (!fileParent.exists()) {fileParent.mkdirs();}// 创建文件if (!testFile.exists())testFile.createNewFile();System.out.println("path:"+testFile.getPath());System.out.println("absolutePath:"+testFile.getAbsolutePath());System.out.println("getFileName:"+testFile.getName());}
}path:D:\filepath\test\test.txt
absolutePath:D:\filepath\test\test.txt
getFileName:test.txt

文件的常用方法

public class FileGet {public static void main(String[] args) {File f = new File("d:/aaa/bbb.java");    //文件绝对路径:d:\aaa\bbb.java System.out.println("文件绝对路径:"+f.getAbsolutePath());//文件构造路径:d:\aaa\bbb.javaSystem.out.println("文件构造路径:"+f.getPath());//文件名称:bbb.javaSystem.out.println("文件名称:"+f.getName());//文件长度:2116字节System.out.println("文件长度:"+f.length()+"字节");//是否存在:trueSystem.out.println(f.exists());}
}

字节流与字符流

1. InputStream
构造方法

// 1. 使用File对象创建流对象
FileInputStream fin = new FileInputStream(new File("G:\\b.txt"));// 2. 使用文件名称创建流对象
FileInputStream fin = new FileInputStream("G:\\b.txt");

读取数据
read():从输入流读取数据的下一个字节
read(byte[] b):从输入流读取一些字节数,并将它们存储到缓冲区b
read(byte[] b, int off, int len):从输入流读取最多 len字节的数据到一个字节数组。

public class FISRead {public static void main(String[] args) throws IOException{FileInputStream fis = new FileInputStream("read.txt");int b;while ((b = fis.read())!=-1) {System.out.println((char)b);}fis.close();}
}

错误读取

public class FISRead {public static void main(String[] args) throws IOException{FileInputStream fis = new FileInputStream("read.txt"); // read.txt文件中内容为abcdeint len;  byte[] b = new byte[2];while (( len= fis.read(b))!=-1) {System.out.println(new String(b));}fis.close();}
}
输出结果:
ab
cd
ed

分析: 由于read.txt文件中内容为abcde,而错误数据d,是由于最后一次读取时,只读取一个字节e,数组中,上次读取的数据没有被完全替换【注意是替换,看下图】,所以要通过len ,获取有效的字节

public class FISRead {public static void main(String[] args) throws IOException{// 使用文件名称创建流对象.FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde// 定义变量,作为有效个数int len ;// 定义字节数组,作为装字节数据的容器   byte[] b = new byte[2];// 循环读取while (( len= fis.read(b))!=-1) {// 每次读取后,把数组的有效字节部分,变成字符串打印System.out.println(new String(b,0,len));//  len 每次读取的有效字节个数}// 关闭资源fis.close();}
}输出结果:
ab
cd
e

2. OuputStream
1. 构造方法

// 1. 使用File对象创建流对象
FileOutputStream fos = new FileOutputStream(new File("G:\\b.txt"));// 2. 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("G:\\b.txt");// 3. 使用File对象创建流对象,并开启数据追加功能
FileOutputStream fos = new FileOutputStream(new File("G:\\b.txt"), true);// 4. 使用文件名创建流对象,并开启数据追加功能
FileOutputStream fos = new FileOutputStream("G:\\b.txt", true)

2. 输出数据

public class IoWrite {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("fos.txt");     // 1. write(int b)fos.write(97);  //2. write(byte[] b)byte[] b = "麻麻我想吃烤山药".getBytes();fos.write(b);//3. write(byte[] b, int off, int len)byte[] b = "abcde".getBytes();fos.write(b,2,2);fos.close();}
}

3. Reader
1. 构造器

// 1. 使用File对象创建流对象
FileReader fr = new FileReader(new File("G:\\b.txt"));// 2. 使用文件名称创建流对象
FileInputStream fos = new FileInputStream("G:\\b.txt");

2. 读取字符

public class FRRead {public static void main(String[] args) throws IOException {FileReader fr = new FileReader("G:\\b.txt");int b;while ((b = fr.read())!=-1) {System.out.println((char)b);}fr.close();}
}

4. Writer
1. 构造方法

// 1. 使用File对象创建流对象
FileWriter fw = new FileWriter(new File("G:\\b.txt"));// 2. 使用文件名称创建流对象
FileWriter fw = new FileWriter("G:\\b.txt");// 3. 使用File对象创建流对象,并开启数据追加功能
FileWriter fw = new FileWriter(new File("G:\\b.txt"), true);// 4. 使用文件名创建流对象,并开启数据追加功能
FileWriter fw = new FileWriter("G:\\b.txt", true)

2. 写出数据
flush :刷新缓冲区,流对象可以继续使用。
close:刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

public class FWWrite {public static void main(String[] args) throws IOException {// 使用文件名称创建流对象FileWriter fw = new FileWriter("fw.txt");     // 写出数据fw.write(97); // 写出第1个字符fw.write('b'); // 写出第2个字符fw.write('C'); // 写出第3个字符fw.close();}
}
输出结果:
abC

缓冲流

原理
创建缓冲流对象时,会创建一个内置的默认8kb的缓冲区数组。

当读数据时,一次I/O就会读取8kb数据,后面read都是读取缓冲区数据,减少系统IO次数,从而提高读的效率。

当写数据时,先把8kb缓冲区填满,然后再调用write把缓冲区8kb数据一次输出,减少系统IO次数,从而提高写的效率。

实例

/*** 使用缓冲字节输入输出流*/
public static void method3() throws IOException {BufferedInputStream bis = new BufferedInputStream(new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/test.jpg"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/copy3.jpg"));byte[] bytes = new byte[1024];int len = 0;while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);}bos.close();bis.close();
}

转换流

InputStreamReader字节流到字符流的桥梁,OutputStreamWriter字符流到字节流的桥梁。
在这里插入图片描述
在这里插入图片描述

对象流

序列化 与 反序列化
在这里插入图片描述

可序列化的两个条件

  • 该类必须实现java.io.Serializable 接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException 。
  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。
public class Employee implements java.io.Serializable {public String name;public String address;public transient int age; // transient瞬态修饰成员,不会被序列化public void addressCheck() {System.out.println("Address  check : " + name + " -- " + address);}
}
public class SerializeDemo{public static void main(String [] args)   {Employee e = new Employee();e.name = "zhangsan";e.address = "beiqinglu";e.age = 20; try {ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));out.writeObject(e);out.close();fileOut.close();} catch(IOException i)   {i.printStackTrace();}}
}

NIO

1. 非阻塞IO
原始的IO并没有缓存,所以线程调用read或 write方法时,必须等待读取或写入所有字节,这时候线程不能干其他事情,所以线程是阻塞的。

非阻塞NIO增加了缓存,线程调用read或 write方法时,不需要等待读取或写入所有字节,可以去做其他的事情。如果一个线程有多个缓存区,那么可以先去缓存区1执行read,然后到缓存区2执行read,这时候返回缓存区1读取数据,这样就避免了在缓存区1中等待。

2. 组件
NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector(选择器)。数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件。因此,单个线程可以监听多个数据通道。

1. Channel
通道可以同时进行读写
在这里插入图片描述
2. Buffer
当向buffer写入数据时,buffer会记录下写了多少数据,一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到读模式,在读模式下可以读取之前写入到buffer的所有数据,一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。

Buffer对象包含三个重要的属性

capacity:Buffer的最大值
position:position表示当前的位置。
limit:在写模式下,表示最多能往Buffer里写多少数据或者最多能读到多少数据。

3. Selector
当你调用Selector的select()或者 selectNow() 方法它只会返回有数据读取的SelectableChannel的实例
在这里插入图片描述

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...