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

    对程序开发人员来讲,文件的读写是很重要的一项技能。可是使人惊讶的是,尽管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类来执行那些基本的任务,好比:移动或复制文件,或读取文件内容到一个字符串集合app

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

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

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

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

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

    文件的复制测试

    Files类提供了一些有用的方法来操做File对象,对Java开发人员来讲,复制一个文件到另外一个文件是件有挑战的工做。可是在Guava里,咱们来看怎样经过Files类完成一样的工做:this

@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方法去覆盖文件,并确保文件已被覆盖

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

相关文章
相关标签/搜索