Scanner 类读取字符串,先导入
java.util.Scanner,创建
Scanner 对象(如关联
System.in),调用
nextLine() 方法获取整行
在 Java 编程中,读取字符串是一项基础且高频的操作,其实现方式需根据输入来源(如控制台、文件、网络流等)选择合适的工具类与方法,以下将从多维度展开详细说明,涵盖主流场景、核心代码、注意事项及对比分析,并提供实用示例与常见问题解答。
按输入来源分类的核心实现方案
从标准输入(控制台)读取字符串
适用于交互式命令行程序,典型工具为 java.util.Scanner 和 java.io.BufferedReader。
| 工具类 | 核心方法 | 特点 | 适用场景 |
|---|---|---|---|
Scanner |
nextLine() |
自动跳过空白行,支持正则表达式过滤(如 next("\d+") 读数字) |
简单交互、混合类型输入解析 |
BufferedReader |
readLine() |
逐行读取,保留换行符前的完整内容,性能优于 Scanner |
高性能控制台输入、长文本处理 |
Console (JDK 6+) |
readLine() |
直接关联系统控制台,无需额外包装 | 跨平台兼容的控制台交互 |
示例 1:使用 Scanner 读取单行字符串
import java.util.Scanner;
public class ReadStringExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // 绑定标准输入流
System.out.print("请输入内容: ");
String input = scanner.nextLine(); // 读取整行(含空格)
System.out.println("你输入的是: " + input);
scanner.close(); // 释放资源
}
}
️ 注意:next() 仅读取到下一个空白字符前,而 nextLine() 会读取整行(包括前后空格),若混合使用两者可能导致残留换行符问题。
示例 2:使用 BufferedReader 提升性能
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class FastReadExample {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入内容: ");
String line = reader.readLine(); // 阻塞等待用户输入
System.out.println("你输入的是: " + line);
reader.close(); // 关闭流
}
}
优势:BufferedReader 内部维护缓冲区,减少底层 I/O 次数,适合高频次、大数据量的输入。
从文件中读取字符串
涉及文件路径定位与字符编码处理,常用组合为 FileReader + BufferedReader 或 Files.readAllBytes(Java 7+)。
| 方案 | 关键代码 | 特点 | 局限性 |
|---|---|---|---|
| 传统流式读取 | new FileReader(filePath) → BufferedReader |
灵活控制读取进度,可逐行/按字符读取 | 需手动管理资源关闭 |
| NIO 文件API | Files.readAllBytes(Paths.get(filePath)) |
一次性读取全部内容到字节数组,配合 new String() 转换 |
大文件易导致内存溢出 |
| 第三方库(Apache Commons IO) | FileUtils.readFileToString(new File(filePath), StandardCharsets.UTF_8) |
一行代码完成,自动处理编码与异常 | 依赖外部库 |
示例 3:逐行读取文件内容
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class FileReadExample {
public static void main(String[] args) {
String filePath = "data.txt";
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) { // 逐行读取直至文件末尾
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
️ 关键细节:
- 字符编码:默认使用平台编码(如 Windows 的 GBK),建议显式指定
UTF-8等编码,可通过InputStreamReader构造函数设置。 - 资源管理:使用
try-with-resources语法自动关闭流,避免内存泄漏。 - 大文件优化:对于超过内存容量的文件,应改用
RandomAccessFile或内存映射文件(MappedByteBuffer)。
从网络流中读取字符串
常见于 HTTP 请求响应、Socket 通信等场景,核心是通过 InputStream 转换为字符流。
示例 4:通过 URLConnection 读取网页内容
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class WebReadExample {
public static void main(String[] args) {
try {
URL url = new URL("http://example.com");
URLConnection connection = url.openConnection();
// 设置请求头(可选)
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream(), "UTF-8"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
要点:
- 网络流本质是字节流,需通过
InputStreamReader解码为字符流。 - 注意处理 HTTP 状态码(如 404 Not Found),可通过
connection.getResponseCode()判断。 - 超时设置:
connection.setConnectTimeout(5000);防止长时间阻塞。
通用技巧与最佳实践
字符编码问题
- 痛点:不同系统默认编码不一致(如 Linux 多为 UTF-8,Windows 为 GBK),直接读取可能出现乱码。
- 解决方案:始终显式指定编码格式,
new InputStreamReader(inputStream, StandardCharsets.UTF_8);
- 验证方法:打印字符串的字节数组查看是否符合预期。
异常处理策略
- 受检异常:
IOException必须捕获或声明抛出,推荐使用try-catch块。 - 非受检异常:如
NullPointerException(未初始化流)、UnsupportedEncodingException(错误编码名),需提前校验参数。 - 日志记录:生产环境建议将异常堆栈写入日志而非直接打印。
性能考量
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 小数据量(<1MB) | Scanner 或 BufferedReader |
开发便捷,开销可忽略 |
| 中等数据量(1-10MB) | BufferedReader + 合理缓冲区大小 |
平衡性能与内存占用 |
| 大数据量(>10MB) | 内存映射文件(MappedByteBuffer) |
直接操作磁盘,避免频繁 I/O |
| 实时流处理 | CompletableFuture + 异步读取 |
结合 Reactor 模式提升吞吐量 |
相关问答 FAQs
Q1: 为什么有时用 Scanner.nextLine() 会跳过预期的输入行?
A: 这是由于 Scanner 的内部机制导致的,当之前使用了 nextInt()、nextDouble() 等方法后,这些方法不会消耗行尾的换行符,导致后续的 nextLine() 立即读取到一个空行。
解决方法:在使用数值型方法后,添加一个额外的 nextLine() 消耗残留的换行符。
示例:
Scanner scanner = new Scanner(System.in); int age = scanner.nextInt(); // 输入年龄后按回车 scanner.nextLine(); // 消耗换行符 String name = scanner.nextLine(); // 现在能正确读取姓名
Q2: 如何高效读取非常大的文本文件(如几个GB)?
A: 对于超大文件,应采用以下策略:
- 分块读取:使用
BufferedReader并设置较大的缓冲区(如 8KB),减少 I/O 次数。 - 并行处理:将文件拆分为多个部分,使用多线程或分布式框架(如 Spark)并行处理。
- 内存映射:通过
FileChannel.map()将文件映射到内存,直接操作字节缓冲区。
示例(分块读取):import java.io.; import java.nio.charset.StandardCharsets;
public class LargeFileReader {
public static void main(String[] args) throws IOException {
File file = new File(“large.log”);
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8), 8 1024)) {
String line;
while ((line = reader.readLine()) != null) {
// 处理每一行…
}
}
}
}
---
四、
Java 提供了丰富的字符串读取方案,选择时需综合考虑输入来源、数据量级、性能需求和编码兼容性,对于初学者,`Scanner` 和 `BufferedReader` 是入门首选;对于企业级应用,建议结合 NIO 或第三方库实现高效可靠的文件操作,无论何种场景,始终注意资源管理和异常处理
