Guava库学习:学习Guava Files系列(一)

Stella981
• 阅读 1002

    对程序开发人员来说,文件的读写是很重要的一项技能。但是令人惊讶的是,尽管Java提供了一个丰富而健壮的I/O库,进行一些基本的文件操作却显得很繁 琐。不过在Java 7中已经发生了一些改变,但那些使用Java 6的就不那么好运了。幸运的是,Guava做了一些我们期望I/O库做的事情,提供了一系列的工具,让我们能够更方便的进行I/O操作。本篇,我们就开始来学习如何使用Guava Files进行一些I/O操作。

    尽管Java 7做了一些改进,并解决了一些Guava的小的问题,但我们发现Guava提供的工具在进行I/O操作时仍然非常有用。本Guava Files系列中,我们将要学习一下内容:

  • 使用Files类来执行那些基本的任务,比如:移动或复制文件,或读取文件内容到一个字符串集合

  • Closer类,提供了一种非常干净的方式,确保Closeable实例被正确的关闭

  • ByteSource 和 CharSource类,提供了不可变的输入流(Input)和读(Reader)

  • ByteSink 和 CharSink类,提供了不可变的输出流(Output)和写(Writer)

  • CharStreams和ByteStreams类,为读Readers、写Writers、输入流InputStreams、输出流OutputStreams 提供了一些静态的实用方法

  • BaseEncoding类,提供了编码和解码字节序列和ASCII字符的方法

文件的复制

    Files类提供了一些有用的方法来操作File对象,对Java开发人员来说,复制一个文件到另一个文件是件有挑战的工作。但是在Guava里,我们来看怎样通过Files类完成同样的工作:

@Test
public void testCopyFile() throws IOException {
    File original = new File("D:\\test.txt");
    File copy = new File("D:\\test2.txt");
    Files.copy(original, copy);
}

文件的移动/重命名

    同样,Java中移动文件也和复制一样繁琐。在Guava里,则非常的简单,代码如下:

@Test
public void testMoveFile() throws IOException {
    File original = new File("D:\\test.txt");
    File newFile = new File("D:\\test2.txt");
    Files.move(original, newFile);
}

像字符串一样处理文件

    有些时候我们需要操作或使用文件的字符串表示。Files类提供了一些方法,能够将文件读取到一个字符串集合,返回文件的第一行字符串,将一个完整的文件 的内容读入一个字符串。下面的例子,会介绍通过调用Files.readLines方法将文件读取到一个string集合中:

@Test
public void readFileIntoListOfStringsTest() throws IOException {
    File file = new File("D:\\test2.txt");
    List<String> expectedLines = Lists.newArrayList("hello world", "this is realfighter", "www.xx566.com");
    List<String> readLines = Files.readLines(file,
            Charsets.UTF_8);
    assertThat(expectedLines, is(readLines));
}

上面的例子中,我们使用了一个单元测试来确认从简单文件中读取的三行内容与我们的期望相同。每行内容中的换行符被删除,但其他空白的字符则保留。Files.readLines还可以接收LineProcessor实例作为额外的附加参数。每一行内容都参数LineProcessor.processLine方法,该方法返回一个布尔值。LineProcessor实例会持续读取文件中的行,直到文件读取完毕或LineProcessor.processLine方法返回false。假设,我们有包含如下信息的一个文件,是一些书本的信息:

"Savage Tom",Being A Great Cook,Acme Publishers,ISBN- 123456,29.99,1
"Smith Jeff",Art is Fun,Acme Publishers,ISBN-456789,19.99,2
"Vandeley Art",Be an Architect,Acme Publishers,ISBN- 234567,49.99,3
"Jones Fred",History of Football,Acme Publishers,ISBN- 345678,24.99,4
"Timpton Patty",Gardening My Way,Acme Publishers,ISBN- 4567891,34.99,5

我们想要抽取出每行数据中的书本的标题。为了完成这项任务,我们需要对LineProcessor接口做如下的实现:

class ToListLineProcessor implements LineProcessor<List<String>> {
    private static final Splitter splitter = Splitter.on(",");
    private List<String> bookTitles = Lists.newArrayList();
    private static final int TITLE_INDEX = 1;
    @Override
    public boolean processLine(String line) throws IOException {
        bookTitles.add(Iterables.get(splitter.split(line), TITLE_INDEX));
        return true;
    }
    @Override
    public List<String> getResult() {
        return bookTitles;
    }
}

在这里我们将使用逗号分隔每行,获取这本书的标题,是每行中的第二项,并将标题添加到一个字符串集合中。注意,我们使用了Iterables类,使用了静态的Iterables.get方法,来获取书本的标题。processLine方法总是返回true,因为我们需要获取所有文件中的书本名,下面是对LineProcessor实例的单元测试:

@Test
public void readLinesWithProcessor() throws Exception {
    File file = new File("D:\\test2.txt");
    List<String> expectedLines = Lists.newArrayList("Being A Great Cook", "Art is Fun",
            "Be an Architect", "History of Football", "Gardening My Way");
    List<String> readLines = Files.readLines(file, Charsets.UTF_8,
            new ToListLineProcessor());
    assertThat(expectedLines, is(readLines));
}

    在这个例子中,我们简单的获取了读取了所有的输入,但是我们可以很容易的通过一些条件只获取n行或过滤一些数据。

文件的哈希值

    在Java中生成文件的哈希值似乎需要很多的代码操作,但在Guava中,它变得非常简单。Files类拥有一个hash方法,使用代码如下:

@Test
public void testFilesHashing() throws Exception{
    File file = new File("D:\\test2.txt");
    HashCode hashCode = Files.hash(file, Hashing.md5());
    System.out.println(hashCode);
}

    上面的例子中,为了使用Files.hash方法,我们提供了File对象和HashFuction实例,我们使用了一个实现MD5算法的hash函数,并且方法返回一个HashCode对象。Hash函数将在下一个系列中介绍,敬请期待。

文件写

当我们使用输入/输出流时,我们经常需要编写以下几步的代码:

  1. 打开输入/输出流。

  2. 将字节读入/读出。

  3. 读取完毕,确保所有的资源都在finally代码块中关闭。

    当我们不得不一遍遍的重复这个过程,就很容易出错,并会使得代码越来越不清晰和难以维护。Files类为我们提供了方便,能够很容易的 在文件的写/追加数据或读取文件内容到字节数组。大部分那些我们需要特别关注的打开或关闭资源的代码,只需要简单的一行代码。

文件写和追加数据

    一个简单的文件的写和追加数据例子,代码如下:

@Test
public void appendingWritingToFileTest() throws IOException {
    File file = new File("D:\\test2.txt");
    file.deleteOnExit();
    String hamletQuoteStart = "To be, or not to be";
    Files.write(hamletQuoteStart, file, Charsets.UTF_8);
    assertThat(Files.toString(file, Charsets.UTF_8), is(hamletQuoteStart));
    String hamletQuoteEnd = ",that is the question";
    Files.append(hamletQuoteEnd, file, Charsets.UTF_8);
    assertThat(Files.toString(file, Charsets.UTF_8), is(hamletQuoteStart + hamletQuoteEnd));
    String overwrite = "Overwriting the file";
    Files.write(overwrite, file, Charsets.UTF_8);
    assertThat(Files.toString(file, Charsets.UTF_8), is(overwrite));
}

    在这个例子中,我们使用单元测试做了如下几件事情:

  1. 创建一个测试的文件,并确保JVM中不存在同名的文件

  2. 我们使用Files.write方法向文件写入一个字符,并确保写入成功

  3. 之后我们使用了Files.append方法追加了另一个字符到文件,并同样确认文件中已经存在追加的内容

  4. 最后,我们再次使用Files.write方法去覆盖文件,并确保文件已被覆盖

    虽然这是一个简单的例子,但请注意,我们三次对文件进行写,我们不曾编写任何打开或关闭资源的代码。因此,我们的代码变得简单易读,更重要的是,不容易出现错误。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
sql注入
反引号是个比较特别的字符,下面记录下怎么利用0x00SQL注入反引号可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景,下面具体说下1)表名payload:select\from\users\whereuser\_id1limit0,1;!(https://o
Stella981 Stella981
3年前
Guava File操作
Java的基本API对文件的操作很繁琐,为了向文件中写入一行文本,都需要写十几行的代码。guava对此作了很多改进,提供了很多方便的操作。一.Guava的文件写入Guava的Files类中提供了几个write方法来简化向文件中写入内容的操作,下面的例子演示 Files.write(byte\\,File)(https://www.o
Stella981 Stella981
3年前
Guava库学习:学习Guava Files系列(二)
  上一篇,Guava库学习:学习GuavaFiles系列(一)(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.xx566.com%2Fdetail%2F216.html)中,我们简单的学习了使用Files进行文件的读写等常用操作,本篇我们继续进行GuavaFiles系列
Stella981 Stella981
3年前
Guava库学习:Guava 零碎知识
    这将是Guava库学习系列的最后一篇,但是仍然包含许多零零碎碎的知识。虽然不可能覆盖所有Guava涉及的知识,但我们会竭尽所能。本篇将会介绍一些Guava中有用的工具,并不需要再开一个系列。本篇学习的一些工具可能并不会经常使用,但当你需要时,它是必不可少的。接下来,开始本篇的学习。本篇,我们将主要学习以下内容:Hashing、BloomFilter
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这