Skip to content

Java IO流面试题

1. IO流的基本概念

问题:什么是IO流?Java中的IO流有哪些分类?

答案

  • IO流:输入输出流,用于处理数据的输入和输出操作。
  • 分类
    • 按流向:输入流和输出流。
    • 按数据类型:字节流和字符流。
    • 按功能:节点流和处理流。

2. 字节流和字符流的区别

问题:字节流和字符流有什么区别?

答案

特性字节流字符流
处理单位字节(8位)字符(16位)
基类InputStream、OutputStreamReader、Writer
适用场景二进制数据、图片、视频等文本数据
缓冲区无缓冲有缓冲

3. 常见的IO流类

问题:Java中有哪些常见的IO流类?

答案

  • 字节流
    • InputStream:FileInputStream、ByteArrayInputStream、BufferedInputStream等。
    • OutputStream:FileOutputStream、ByteArrayOutputStream、BufferedOutputStream等。
  • 字符流
    • Reader:FileReader、StringReader、BufferedReader等。
    • Writer:FileWriter、StringWriter、BufferedWriter等。

4. 文件操作

问题:如何进行文件操作?

答案

java
// 创建文件
File file = new File("test.txt");
if (!file.exists()) {
    file.createNewFile();
}

// 写入文件
try (FileWriter writer = new FileWriter(file)) {
    writer.write("Hello, World!");
}

// 读取文件
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
}

// 删除文件
file.delete();

5. NIO

问题:什么是NIO?NIO和IO有什么区别?

答案

  • NIO(New IO):Java 1.4引入的新IO API,提供了非阻塞IO操作。
  • 区别
    • IO是面向流的,NIO是面向缓冲区的。
    • IO是阻塞的,NIO是非阻塞的。
    • NIO提供了选择器(Selector)机制,可以管理多个通道。

6. NIO的核心组件

问题:NIO的核心组件有哪些?

答案

  • Buffer(缓冲区):用于存储数据的容器。
  • Channel(通道):用于数据的传输通道。
  • Selector(选择器):用于管理多个通道的选择器。

7. Buffer的使用

问题:如何使用Buffer?

答案

java
// 创建Buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);

// 写入数据
buffer.put("Hello, World!".getBytes());

// 切换到读模式
buffer.flip();

// 读取数据
while (buffer.hasRemaining()) {
    byte b = buffer.get();
    System.out.print((char) b);
}

// 清空Buffer
buffer.clear();

8. Channel的使用

问题:如何使用Channel?

答案

java
// 创建Channel
FileChannel channel = new FileInputStream("test.txt").getChannel();

// 创建Buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);

// 读取数据
channel.read(buffer);

// 切换到读模式
buffer.flip();

// 读取数据
while (buffer.hasRemaining()) {
    byte b = buffer.get();
    System.out.print((char) b);
}

// 关闭Channel
channel.close();

9. 序列化和反序列化

问题:什么是序列化和反序列化?如何实现?

答案

  • 序列化:将对象转换为字节序列的过程。
  • 反序列化:将字节序列转换为对象的过程。
  • 实现方式
java
// 实现Serializable接口
public class Person implements Serializable {
    private String name;
    private int age;
    // getters and setters
}

// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
    Person person = new Person();
    person.setName("John");
    person.setAge(30);
    oos.writeObject(person);
}

// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
    Person person = (Person) ois.readObject();
    System.out.println(person.getName()); // John
    System.out.println(person.getAge()); // 30
}

10. transient关键字

问题:transient关键字有什么作用?

答案: transient关键字用于标记不需要序列化的字段。

示例

java
public class Person implements Serializable {
    private String name;
    private transient int age; // 不会被序列化
    // getters and setters
}

11. try-with-resources

问题:什么是try-with-resources?有什么作用?

答案

  • try-with-resources:Java 7引入的语法糖,用于自动关闭资源。
  • 作用:简化资源管理,避免资源泄漏。

示例

java
// 传统方式
FileInputStream fis = null;
try {
    fis = new FileInputStream("test.txt");
    // 使用资源
} finally {
    if (fis != null) {
        fis.close();
    }
}

// try-with-resources方式
try (FileInputStream fis = new FileInputStream("test.txt")) {
    // 使用资源
}

12. Files类

问题:Files类提供了哪些常用方法?

答案

  • 文件操作
    • Files.createFile(Path path):创建文件。
    • Files.delete(Path path):删除文件。
    • Files.copy(Path source, Path target):复制文件。
    • Files.move(Path source, Path target):移动文件。
  • 目录操作
    • Files.createDirectory(Path dir):创建目录。
    • Files.createDirectories(Path dir):创建多级目录。
    • Files.list(Path dir):列出目录内容。
    • Files.walk(Path start):遍历目录树。

13. Path类

问题:Path类提供了哪些常用方法?

答案

  • Path getFileName():获取文件名。
  • Path getParent():获取父路径。
  • Path getRoot():获取根路径。
  • int getNameCount():获取名称数量。
  • Path getName(int index):获取指定索引的名称。
  • Path normalize():规范化路径。
  • Path toAbsolutePath():转换为绝对路径。
  • Path resolve(Path other):解析路径。

14. 文件过滤器

问题:如何过滤文件?

答案

java
// 使用FilenameFilter
File dir = new File(".");
String[] files = dir.list(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
        return name.endsWith(".txt");
    }
});

// 使用FileFilter
File[] files = dir.listFiles(new FileFilter() {
    @Override
    public boolean accept(File pathname) {
        return pathname.isFile() && pathname.getName().endsWith(".txt");
    }
});

// 使用Lambda表达式
String[] files = dir.list((dir, name) -> name.endsWith(".txt"));

15. 文件监听

问题:如何监听文件变化?

答案

java
// 创建WatchService
WatchService watchService = FileSystems.getDefault().newWatchService();

// 注册监听目录
Path dir = Paths.get(".");
dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, 
    StandardWatchEventKinds.ENTRY_DELETE, 
    StandardWatchEventKinds.ENTRY_MODIFY);

// 监听事件
while (true) {
    WatchKey key = watchService.take();
    for (WatchEvent<?> event : key.pollEvents()) {
        System.out.println(event.kind() + ": " + event.context());
    }
    key.reset();
}

16. 内存映射文件

问题:什么是内存映射文件?如何使用?

答案

  • 内存映射文件:将文件映射到内存中,通过内存操作文件。
  • 使用方式
java
// 创建RandomAccessFile
RandomAccessFile file = new RandomAccessFile("test.txt", "rw");

// 创建MappedByteBuffer
MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, file.length());

// 读写数据
buffer.put(0, (byte) 'H');
byte b = buffer.get(0);

// 关闭文件
file.close();

17. 管道流

问题:什么是管道流?如何使用?

答案

  • 管道流:用于线程间通信的流。
  • 使用方式
java
// 创建管道流
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream(pis);

// 写入线程
new Thread(() -> {
    try {
        pos.write("Hello, World!".getBytes());
        pos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}).start();

// 读取线程
new Thread(() -> {
    try {
        byte[] buffer = new byte[1024];
        int len = pis.read(buffer);
        System.out.println(new String(buffer, 0, len));
        pis.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}).start();

18. 压缩流

问题:如何使用压缩流?

答案

java
// 压缩文件
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("test.zip"))) {
    ZipEntry entry = new ZipEntry("test.txt");
    zos.putNextEntry(entry);
    zos.write("Hello, World!".getBytes());
    zos.closeEntry();
}

// 解压文件
try (ZipInputStream zis = new ZipInputStream(new FileInputStream("test.zip"))) {
    ZipEntry entry;
    while ((entry = zis.getNextEntry()) != null) {
        System.out.println(entry.getName());
        byte[] buffer = new byte[1024];
        int len;
        while ((len = zis.read(buffer)) > 0) {
            System.out.write(buffer, 0, len);
        }
        zis.closeEntry();
    }
}

19. 字符编码

问题:什么是字符编码?常见的字符编码有哪些?

答案

  • 字符编码:将字符转换为字节的方式。
  • 常见编码
    • ASCII:美国信息交换标准码,7位编码。
    • ISO-8859-1:西欧字符编码,8位编码。
    • GBK:中文字符编码,双字节编码。
    • UTF-8:可变长度编码,支持所有Unicode字符。
    • UTF-16:固定长度编码,支持所有Unicode字符。

20. 字符集

问题:Java中如何处理字符集?

答案

java
// 获取默认字符集
Charset defaultCharset = Charset.defaultCharset();
System.out.println(defaultCharset); // UTF-8

// 获取指定字符集
Charset charset = Charset.forName("UTF-8");

// 编码
String str = "Hello, 世界";
byte[] bytes = str.getBytes(charset);

// 解码
String decoded = new String(bytes, charset);

21. 缓冲流

问题:什么是缓冲流?有什么作用?

答案

  • 缓冲流:在内存中创建缓冲区,减少IO操作次数。
  • 作用:提高IO性能。

示例

java
// 不使用缓冲流
try (FileInputStream fis = new FileInputStream("test.txt")) {
    int b;
    while ((b = fis.read()) != -1) {
        System.out.print((char) b);
    }
}

// 使用缓冲流
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.txt"))) {
    int b;
    while ((b = bis.read()) != -1) {
        System.out.print((char) b);
    }
}

22. 数据流

问题:什么是数据流?如何使用?

答案

  • 数据流:用于读写基本数据类型的流。
  • 使用方式
java
// 写入数据
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.dat"))) {
    dos.writeInt(123);
    dos.writeDouble(3.14);
    dos.writeUTF("Hello");
}

// 读取数据
try (DataInputStream dis = new DataInputStream(new FileInputStream("data.dat"))) {
    int i = dis.readInt();
    double d = dis.readDouble();
    String s = dis.readUTF();
    System.out.println(i); // 123
    System.out.println(d); // 3.14
    System.out.println(s); // Hello
}

23. 对象流

问题:什么是对象流?如何使用?

答案

  • 对象流:用于读写对象的流。
  • 使用方式
java
// 写入对象
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("objects.dat"))) {
    oos.writeObject("Hello");
    oos.writeObject(123);
    oos.writeObject(3.14);
}

// 读取对象
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objects.dat"))) {
    String s = (String) ois.readObject();
    Integer i = (Integer) ois.readObject();
    Double d = (Double) ois.readObject();
    System.out.println(s); // Hello
    System.out.println(i); // 123
    System.out.println(d); // 3.14
}

24. PrintStream和PrintWriter

问题:PrintStream和PrintWriter有什么区别?

答案

  • PrintStream:字节流,用于打印字节。
  • PrintWriter:字符流,用于打印字符。
  • 共同点:都提供了方便的打印方法。

示例

java
// PrintStream
PrintStream ps = new PrintStream("output.txt");
ps.println("Hello, World!");
ps.close();

// PrintWriter
PrintWriter pw = new PrintWriter("output.txt");
pw.println("Hello, World!");
pw.close();

25. 标准输入输出

问题:Java中的标准输入输出是什么?

答案

  • System.in:标准输入流,对应键盘输入。
  • System.out:标准输出流,对应屏幕输出。
  • System.err:标准错误流,对应屏幕输出。

示例

java
// 读取标准输入
Scanner scanner = new Scanner(System.in);
System.out.print("请输入:");
String input = scanner.nextLine();
System.out.println("输入:" + input);

// 输出到标准输出
System.out.println("Hello, World!");

// 输出到标准错误
System.err.println("Error!");