1. 简介
本教程将介绍如何使用 Guava IO 工具类来实现文件的写入与读取操作。我们将通过多个示例展示 Guava 提供的各种便捷 API,帮助开发者更优雅地处理文件 I/O。
2. 使用 Files 类进行文件写入
我们从一个最简单的例子开始:使用 Files.write()
方法将字符串写入到文件中:
@Test
public void whenWriteUsingFiles_thenWritten() throws IOException {
String expectedValue = "Hello world";
File file = new File("test.txt");
Files.write(expectedValue, file, Charsets.UTF_8);
String result = Files.toString(file, Charsets.UTF_8);
assertEquals(expectedValue, result);
}
⚠️ 注意:还可以使用 Files.append()
方法向已存在的文件追加内容。
3. 使用 CharSink 写入文件
接下来,我们使用 CharSink
来完成写入操作。首先通过 Files.asCharSink()
获取一个 CharSink
实例,然后调用其方法写入数据:
@Test
public void whenWriteUsingCharSink_thenWritten() throws IOException {
String expectedValue = "Hello world";
File file = new File("test.txt");
CharSink sink = Files.asCharSink(file, Charsets.UTF_8);
sink.write(expectedValue);
String result = Files.toString(file, Charsets.UTF_8);
assertEquals(expectedValue, result);
}
✅ 此外,CharSink
还支持批量写入多行内容。例如下面这个示例中,我们将一组名字写入文件,并以空格作为分隔符:
@Test
public void whenWriteMultipleLinesUsingCharSink_thenWritten() throws IOException {
List<String> names = Lists.newArrayList("John", "Jane", "Adam", "Tom");
File file = new File("test.txt");
CharSink sink = Files.asCharSink(file, Charsets.UTF_8);
sink.writeLines(names, " ");
String result = Files.toString(file, Charsets.UTF_8);
String expectedValue = Joiner.on(" ").join(names);
assertEquals(expectedValue, result.trim());
}
4. 使用 ByteSink 写入字节
如果需要直接写入原始字节,可以使用 ByteSink
。下面的示例演示了如何通过 Files.asByteSink()
获取 ByteSink
并写入字节数组:
@Test
public void whenWriteUsingByteSink_thenWritten() throws IOException {
String expectedValue = "Hello world";
File file = new File("test.txt");
ByteSink sink = Files.asByteSink(file);
sink.write(expectedValue.getBytes());
String result = Files.toString(file, Charsets.UTF_8);
assertEquals(expectedValue, result);
}
💡 小贴士:可以通过 byteSink.asCharSink()
轻松在 ByteSink
和 CharSink
之间转换。
5. 使用 Files 类读取文件
接下来,我们来看看如何使用 Files
类读取文件内容。
✅ 最简单的方式是使用 Files.toString()
一次性读取整个文件内容为字符串:
@Test
public void whenReadUsingFiles_thenRead() throws IOException {
String expectedValue = "Hello world";
File file = new File("test.txt");
String result = Files.toString(file, Charsets.UTF_8);
assertEquals(expectedValue, result);
}
此外,也可以使用 Files.readLines()
将文件内容按行读入为一个字符串列表:
@Test
public void whenReadMultipleLinesUsingFiles_thenRead() throws IOException {
File file = new File("test.txt");
List<String> result = Files.readLines(file, Charsets.UTF_8);
assertThat(result, contains("John", "Jane", "Adam", "Tom"));
}
📌 若只需要读取第一行内容,可使用 Files.readFirstLine()
方法。
6. 使用 CharSource 读取文件
现在我们来看如何使用 CharSource
来读取文件内容。
首先通过 Files.asCharSource()
获取 CharSource
实例,再调用其 read()
方法获取完整内容:
@Test
public void whenReadUsingCharSource_thenRead() throws IOException {
String expectedValue = "Hello world";
File file = new File("test.txt");
CharSource source = Files.asCharSource(file, Charsets.UTF_8);
String result = source.read();
assertEquals(expectedValue, result);
}
✅ 更有趣的是,多个 CharSource
可以合并成一个统一视图进行读取。如下示例展示了两个文件内容的拼接读取:
@Test
public void whenReadMultipleCharSources_thenRead() throws IOException {
String expectedValue = "Hello worldTest";
File file1 = new File("test1.txt");
File file2 = new File("test2.txt");
CharSource source1 = Files.asCharSource(file1, Charsets.UTF_8);
CharSource source2 = Files.asCharSource(file2, Charsets.UTF_8);
CharSource source = CharSource.concat(source1, source2);
String result = source.read();
assertEquals(expectedValue, result);
}
7. 使用 CharStreams 读取文件
我们可以借助 CharStreams
工具类,配合 FileReader
将文件内容读入为字符串:
@Test
public void whenReadUsingCharStream_thenRead() throws IOException {
String expectedValue = "Hello world";
FileReader reader = new FileReader("test.txt");
String result = CharStreams.toString(reader);
assertEquals(expectedValue, result);
reader.close();
}
⚠️ 别忘了手动关闭 reader
,避免资源泄露。
8. 使用 ByteSource 读取字节
如果需要读取原始字节内容,可以使用 ByteSource
:
@Test
public void whenReadUsingByteSource_thenRead() throws IOException {
String expectedValue = "Hello world";
File file = new File("test.txt");
ByteSource source = Files.asByteSource(file);
byte[] result = source.read();
assertEquals(expectedValue, new String(result));
}
✅ 此外,ByteSource
支持从指定偏移量开始读取,这在处理大文件时尤其有用:
@Test
public void whenReadAfterOffsetUsingByteSource_thenRead() throws IOException {
String expectedValue = "lo world";
File file = new File("test.txt");
long offset = 3;
long len = 1000;
ByteSource source = Files.asByteSource(file).slice(offset, len);
byte[] result = source.read();
assertEquals(expectedValue, new String(result));
}
💡 你也可以使用 byteSource.asCharSource()
转换为字符源进行读取。
9. 使用 ByteStreams 读取字节
同样,我们可以使用 ByteStreams
配合 FileInputStream
来读取字节数据:
@Test
public void whenReadUsingByteStream_thenRead() throws IOException {
String expectedValue = "Hello world";
FileInputStream reader = new FileInputStream("test.txt");
byte[] result = ByteStreams.toByteArray(reader);
reader.close();
assertEquals(expectedValue, new String(result));
}
⚠️ 同样需要注意关闭流资源。
10. 使用 Resources 读取 ClassPath 下的文件
最后,如果你要读取的是位于 classpath 中的资源文件(如配置文件),可以使用 Resources
工具类:
@Test
public void whenReadUsingResources_thenRead() throws IOException {
String expectedValue = "Hello world";
URL url = Resources.getResource("test.txt");
String result = Resources.toString(url, Charsets.UTF_8);
assertEquals(expectedValue, result);
}
📌 这种方式非常适合读取打包进 jar 包中的静态资源。
11. 总结
本文介绍了使用 Guava IO 提供的一系列工具类和接口,如 Files
, CharSink
, ByteSink
, CharSource
, ByteSource
等,来进行文件的读写操作。
所有示例代码均可在 GitHub 项目 中找到,这是一个基于 Eclipse 的 Maven 项目,导入即可运行。
✅ Guava 的这些 IO 工具不仅简洁高效,还隐藏了许多繁琐的 try-catch 和资源管理逻辑,值得在日常开发中广泛使用。