Java- IO 及其相关面试题(上)

简介: Java- IO 及其相关面试题(上)

目录

一、前言

    Java IO是Java编程中非常重要的一部分,它提供了丰富的输入和输出功能,可以实现对文件、网络和其他设备的读取和写入操作。在开发中,Java IO广泛应用于文件处理、网络通信、序列化等场景。

Java IO主要涉及两个核心概念:输入流和输出流。输入流用于读取数据,输出流用于写入数据。它们支持字节流和字符流两种类型。字节流以字节为单位进行操作,适用于二进制文件或纯文本文件。字符流以字符为单位进行操作,适用于处理文本文件。


   Java IO还提供了标准IO和NIO两种模式。传统的标准IO模式以流的方式进行操作,适用于较小的数据量和较低的并发处理需求。新IO(NIO)模式则基于通道和缓冲区进行操作,适用于高并发、高吞吐量的场景。


   接下来,我们将详细介绍字节流和字符流的操作方法,并给出相应的代码示例。

二、Java IO 概述

输入和输出流

2.1.1 定义

    输入流(InputStream)和输出流(OutputStream)是Java的I/O类库中的基本概念。输入流用于从外部源(例如文件、网络连接等)读取数据,而输出流用于将数据写入到外部目标(例如文件、网络连接等)。


   输入流提供了一种逐个读取数据的方式,可以使用一些方法来读取不同类型的数据,如readByte、readChar、readInt等。输出流则提供了一些方法来写入不同类型的数据,如writeByte、writeChar、writeInt等。输入流和输出流可以用于处理各种不同的数据源和目标,例如文件、网络套接字、内存缓冲区等。


   在应用中,输入流常用于读取文件内容、读取网络数据等场景,而输出流常用于将数据写入文件、将数据发送到网络等场景。

2.1.2 代码示例

下面是一个示例,演示如何使用输入流和输出流来读写文件:

import java.io.*;
public class FileIOExample {
    public static void main(String[] args) {
        // 读取文件内容
        try (InputStream inputStream = new FileInputStream("input.txt")) {
            int data = inputStream.read();
            while (data != -1) {
                System.out.print((char) data);
                data = inputStream.read();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 写入文件内容
        try (OutputStream outputStream = new FileOutputStream("output.txt")) {
            String message = "Hello, World!";
            outputStream.write(message.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.2 字节流和字符流

2.2.1 定义

    字节流和字符流是Java I/O类库中的两种不同类型的流。    

字节流(ByteStream)以字节为单位进行读取和写入操作,可以处理任意类型的数据。字节流类库包括InputStream和OutputStream。


   字符流(CharacterStream)以字符为单位进行读取和写入操作,只能处理文本类型的数据。字符流类库包括Reader和Writer。


   字节流和字符流之间的主要区别在于处理的数据类型不同。字节流可以读取和写入任意类型的数据,适用于处理二进制数据和非文本数据。而字符流则专门用于处理文本数据,可以自动进行字符编码和解码,方便读写文本文件。


   在选择流类型时,需要考虑到处理的数据类型。如果处理的是文本数据,应选择字符流;如果处理的是二进制数据或非文本数据,应选择字节流。

2.2.2 代码示例

下面是一个示例,演示如何使用字符流来读写文本文件:

import java.io.*;
public class FileIOExample {
    public static void main(String[] args) {
        // 读取文本文件内容
        try (Reader reader = new FileReader("input.txt")) {
            int data = reader.read();
            while (data != -1) {
                System.out.print((char) data);
                data = reader.read();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 写入文本文件内容
        try (Writer writer = new FileWriter("output.txt")) {
            String message = "Hello, World!";
            writer.write(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.3 标准IO和NIO

    传统的标准IO(IO是指输入输出)是一种同步阻塞的IO模型,它使用InputStream和OutputStream来进行数据的读取和写入操作。
   标准IO的特点是对数据的读取和写入是以阻塞方式进行的,意味着在IO操作完成之前,当前线程会被阻塞,无法进行其他任务。这种模型在处理大量的并发连接时,性能较差。


   NIO(New IO)是Java提供的一种新的IO模型,它使用通道(Channel)和缓冲区(Buffer)来进行数据的读取和写入操作。


下面将会介绍NIO、BIO和AIO的区别以及NIO使用通道(Channel)和缓冲区(Buffer)。

三、字节流和字符流

3.1. 字节流:InputStream和OutputStream

    字节流是处理字节数据的输入输出流的抽象类。常用的字节流类有FileIn putStream、FileOutputStream、ByteArrayInputStream和ByteArrayOutputStream等。

3.1.1. FileInputStream和FileOutputStream

    FileInputStream和FileOutputStream是用于读取和写入文件的字节流类。

以下是一个读取文件内容并打印的示例代码:

try (FileInputStream fis = new FileInputStream("example.txt")) {
    int data;
    while ((data = fis.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

以下是一个写入文件内容的示例代码:

try (FileOutputStream fos = new FileOutputStream("example.txt")) {
    fos.write("Hello, World!".getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

3.1.2. ByteArrayInputStream和ByteArrayOutputStream

   ByteArrayInputStream和ByteArrayOutputStream是用于在内存中读取和写入字节数据的字节流类。

以下是一个从字节数组中读取数据并打印的示例代码:

byte[] data = {65, 66, 67, 68, 69};
try (ByteArrayInputStream bais = new ByteArrayInputStream(data)) {
    int byteData;
    while ((byteData = bais.read()) != -1) {
        System.out.print((char) byteData);
    }
} catch (IOException e) {
    e.printStackTrace();
}

以下是一个将数据写入字节数组并打印的示例代码:

try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
    baos.write("Hello, World!".getBytes());
    byte[] data = baos.toByteArray();
    System.out.println(new String(data));
} catch (IOException e) {
    e.printStackTrace();
}

3.1.3. BufferedInputStream和BufferedOutputStream

    BufferedInputStream和BufferedOutputStream是用于提升IO性能的装饰器类,它们通过在内部提供缓冲区来实现。

以下是一个使用BufferedInputStream读取文件的示例代码:

try (FileInputStream fis = new FileInputStream("example.txt");
    BufferedInputStream bis = new BufferedInputStream(fis)) {
    int data;
    while ((data = bis.read()) != -1) {
        System.out.print((char) data);
    }
} catch (IOException e) {
    e.printStackTrace();
}

以下是一个使用BufferedOutputStream写入文件的示例代码:

try (FileOutputStream fos = new FileOutputStream("example.txt");
    BufferedOutputStream bos = new BufferedOutputStream(fos)) {
    bos.write("Hello, World!".getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

  以上是字节流的基本使用方法和示例代码。接下来,我们将介绍字符流的操作方法。

3.2字符流:Reader和Writer

3.2.1. FileReader和FileWriter:

    FileReader是一个用于读取字符文件的类,而FileWriter是一个用于写入字符文件的类。下面是使用FileReader读取字符文件和使用FileWriter写入字符文件的代码示例:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileExample {
    public static void main(String[] args) {
        // 使用FileReader读取字符文件
        try (FileReader reader = new FileReader("input.txt")) {
            int data;
            while ((data = reader.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 使用FileWriter写入字符文件
        try (FileWriter writer = new FileWriter("output.txt")) {
            writer.write("Hello, World!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  在上面的示例中,使用FileReader读取名为"input.txt"的字符文件,并将其内容打印到控制台上。接下来,使用FileWriter将字符串"Hello, World!"写入名为"output.txt"的字符文件。


3.2.2. InputStreamReader和OutputStreamWriter:

   InputStreamReader是一个字符流和字节流之间的桥梁,它将字节流转换为字符流;而OutputStreamWriter是将字符流转换为字节流的类。

   下面是使用InputStreamReader将字节流转换为字符流,并使用OutputStreamWriter将字符流转换为字节流的代码示例:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class StreamExample {
    public static void main(String[] args) {
        // 使用InputStreamReader将字节流转换为字符流
        try (FileInputStream inputStream = new FileInputStream("input.txt");
             InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8")) {
            int data;
            while ((data = inputStreamReader.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 使用OutputStreamWriter将字符流转换为字节流
        try (FileOutputStream outputStream = new FileOutputStream("output.txt");
             OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "UTF-8")) {
            outputStreamWriter.write("Hello, World!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,使用InputStreamReader将名为"input.txt"的字节流转换为字符流,并将其内容打印到控制台上。

   接下来,使用OutputStreamWriter将字符串"Hello, World!"转换为名为"output.txt"的字节流。


3.2.3. BufferedReader和BufferedWriter:

   BufferedReader和BufferedWriter 是具有缓冲区功能的字符流,可以提高读取和写入字符数据的效率。

   下面是使用BufferedReader读取字符文件和使用BufferedWriter写入字符文件的代码示例:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class BufferExample {
    public static void main(String[] args) {
        // 使用BufferedReader读取字符文件
        try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 使用BufferedWriter写入字符文件
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
            writer.write("Hello, World!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,使用BufferedReader逐行读取名为"input.txt"的字符文件,并将每行内容打印到控制台上。

通过使用BufferedReader和BufferedWriter,可以减少对磁盘的读写次数,从而提高读取和写入字符数据的效率。

四、文件操作

4.1. 文件创建、读取和写入

    文件的创建、读取和写入是文件操作中的基本操作。下面是一些常见的文件操作代码示例:

  1. 创建文件:
file = open("filename.txt", "w")  # 打开文件,并指定写入模式
file.close()  # 关闭文件
  1. 写入文件:
file = open("filename.txt", "w")  # 打开文件,并指定写入模式
file.write("Hello, World!")  # 写入内容
file.close()  # 关闭文件

读取文件:

file = open("filename.txt", "r")  # 打开文件,并指定读取模式
content = file.read()  # 读取文件内容
print(content)  # 打印文件内容
file.close()  # 关闭文件

4.2. 文件复制和移动

    文件复制和移动是常见的文件操作需求。可以使用shutil模块中的函数来执行文件复制和移动。

  1. 文件复制:
import shutil
src_file = "path/to/original_file.txt"
dst_file = "path/to/new_file.txt"
shutil.copy(src_file, dst_file)  # 复制文件
  1. 文件移动:
import shutil
src_file = "path/to/original_file.txt"
dst_dir = "path/to/destination_directory/"
shutil.move(src_file, dst_dir)  # 移动文件

4.3. 文件删除和重命名

文件删除和重命名也是常见的文件操作需求。

  1. 文件删除:
import os
file = "path/to/file.txt"
os.remove(file)  # 删除文件

文件重命名

import os
src_file = "path/to/original_file.txt"
dst_file = "path/to/new_file.txt"
os.rename(src_file, dst_file)  # 重命名文件

4.4. 文件属性和权限

文件属性和权限信息可以使用os模块的函数来获取和设置。

  1. 获取文件信息:
import os
file = "path/to/file.txt"
file_info = os.stat(file)  # 获取文件信息
print(file_info.st_size)  # 打印文件大小
print(file_info.st_mtime)  # 打印文件修改时间

设置文件权限:

import os
file = "path/to/file.txt"
os.chmod(file, 0o777)  # 设置文件权限为 777

请注意,这些代码示例仅作为基本的文件操作示例,需要根据具体的应用程序和操作系统做适当的调整。

五、网络通信

5.1. Socket编程基础

    Socket编程是一种在计算机网络中进行通信的基本方式。它允许不同的计算机之间通过网络进行数据传输。

Socket编程的基本概念:

服务器端和客户端:在Socket编程中,通信的一方被称为服务器端,而另一方被称为客户端。服务器端通常绑定到一个特定的IP地址和端口,并在该端口上监听客户端的请求。


IP地址和端口:IP地址是网络中唯一标识一个主机的地址,端口是用于标识一个进程的数字。


套接字(Socket):套接字是通信的端点,它在客户端和服务器端之间建立连接,并通过连接进行数据传输。

   以下是一个简单的Socket编程示例,展示了服务器端和客户端的基本代码:

5.2. 服务器端示例代码

import java.io.File;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.FileNotFoundException;
public class FileOperations {
    public static void main(String[] args) {
        createFile();
        writeFile();
        readFile();
        copyFile();
        moveFile();
        deleteFile();
        renameFile();
    }
    public static void createFile() {
        try {
            File file = new File("filename.txt");
            if (file.createNewFile()) {
                System.out.println("File created: " + file.getName());
            } else {
                System.out.println("File already exists.");
            }
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
    public static void writeFile() {
        try {
            FileWriter writer = new FileWriter("filename.txt");
            writer.write("Hello, World!");
            writer.close();
            System.out.println("Successfully wrote to the file.");
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
    public static void readFile() {
        try {
            BufferedReader reader = new BufferedReader(new FileReader("filename.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            reader.close();
        } catch (FileNotFoundException e) {
            System.out.println("File not found.");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
    public static void copyFile() {
        File srcFile = new File("path/to/original_file.txt");
        File destFile = new File("path/to/new_file.txt");
        try {
            Files.copy(srcFile.toPath(), destFile.toPath());
            System.out.println("File copied successfully.");
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
    public static void moveFile() {
        File srcFile = new File("path/to/original_file.txt");
        File destDir = new File("path/to/destination_directory/");
        try {
            Files.move(srcFile.toPath(), destDir.toPath().resolve(srcFile.getName()));
            System.out.println("File moved successfully.");
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
    public static void deleteFile() {
        File file = new File("path/to/file.txt");
        if (file.delete()) {
            System.out.println("File deleted: " + file.getName());
        } else {
            System.out.println("Failed to delete the file.");
        }
    }
    public static void renameFile() {
        File srcFile = new File("path/to/original_file.txt");
        File destFile = new File("path/to/new_file.txt");
        if (srcFile.renameTo(destFile)) {
            System.out.println("File renamed successfully.");
        } else {
            System.out.println("Failed to rename the file.");
        }
    }
}

5.3. 客户端示例代码

import java.io.*;
import java.net.*;
public class Client {
    public static void main(String[] args) {
        try {
            // 创建客户端套接字
            Socket clientSocket = new Socket("localhost", 8888); // 服务器的IP地址和端口号
            // 发送数据给服务器
            String message = "Hello, server!";
            OutputStream outputStream = clientSocket.getOutputStream();
            outputStream.write(message.getBytes());
            // 接收服务器发送的数据
            InputStream inputStream = clientSocket.getInputStream();
            byte[] buffer = new byte[1024];
            int length = inputStream.read(buffer);
            String data = new String(buffer, 0, length);
            System.out.println("收到服务器消息:" + data);
            // 关闭连接
            clientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

请注意,这些代码示例仅作为基本的Socket编程示例,并可能需要根据具体的应用程序和网络环境做适当的调整。

相关文章
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
9天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
14天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
10天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
34 4
|
11天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
51 4
|
1月前
|
存储 安全 算法
Java面试题之Java集合面试题 50道(带答案)
这篇文章提供了50道Java集合框架的面试题及其答案,涵盖了集合的基础知识、底层数据结构、不同集合类的特点和用法,以及一些高级主题如并发集合的使用。
83 1
Java面试题之Java集合面试题 50道(带答案)
|
1月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
67 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
23天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
51 5
|
22天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
18 1
|
1月前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
28 3