Java Okio-更加高效易用的IO库

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119997762
本文出自【赵彦军的博客】

文章目录

okio简介

Okio是一个库,它补充了java.io和java.nio,使访问、存储和处理数据变得更加容易。

OkHttp的的 io 功能就是 okio 提供的,OkHttp是Android中包含的一个功能强大的HTTP客户端。

github地址:https://github.com/square/okio

api主页:https://square.github.io/okio/

maven地址:https://mvnrepository.com/artifact/com.squareup.okio/okio

依赖引入

implementation group: 'com.squareup.okio', name: 'okio', version: '2.10.0'

使用读取数据

练习1:读取文本


    /**
     * 读取文件中的文本
     * @param file
     * @throws IOException
     */
    public void readFile(File file) throws IOException {
        try (Source fileSource = Okio.source(file)) {
            Buffer buffer = new Buffer();
            fileSource.read(buffer, 1024);
            while (true) {
                String line = buffer.readUtf8Line();
                if (line == null) break;
                System.out.println(line);
            }
        }
    }

可以看到Source 就相当于 InputStream , 我们看看 Okio.source(file) 的源码

/** Returns a source that reads from `file`. */
@Throws(FileNotFoundException::class)
fun File.source(): Source = inputStream().source()

再看看 inputStream() 方法

@kotlin.internal.InlineOnly
public inline fun File.inputStream(): FileInputStream {
    return FileInputStream(this)
}

是不是很熟悉,还是 Java IO 那一套。只不过是封装了一层。

我们看看如何创建一个 Source ,它提供了几个方法

Okio.source(InputStream input)
Okio.source(File file)
Okio.source(Socket socket)

还有一点,okio 最新版本都用kotlin重新实现了,我们看看,上面的代码如果用 kotlin 写是什么样子的。

 /**
     * 读取文件中的文本
     * @param file
     * @throws IOException
     */
    @Throws(IOException::class)
    fun readFile(file: File) {
        file.source().use { fileSource ->
            val buffer = Buffer()
            fileSource.read(buffer, 1024)
            while (true) {
                val line = buffer.readUtf8Line() ?: break
                println(line)
            }
        }
    }

是不是简介了不少。

我们用了一个 Buffer() 类做缓冲类,我们看看它的继承关系:

class Buffer : BufferedSource, BufferedSink, Cloneable, ByteChannel {

注意事项:

我们定义了 fileSource.read(buffer, 1024) , 这句话的含义是从文件读数据存入 Buffer 中,最大存入 1024 个字节,返回的是字节个数,如果文件读完了,返回 -1 。

所以完整读取文本文件的代码为:

    public void readFile(File file) throws IOException {
        try (Source fileSource = Okio.source(file)) {
            Buffer buffer = new Buffer();
            while (fileSource.read(buffer, 1024) != -1) {
                while (true) {
                    //一次读一行
                    String line = buffer.readUtf8Line();
                    if (line == null) break;
                    System.out.println(line);
                }
            }
        }
    }

readUtf8Line()一次读一行,有没有方法一次把 buffer 里面内容读完,也有的 buffer.readUtf8() , 所以代码可以改成如下

  /**
     * 读取文件中的文本
     *
     * @param file
     * @throws IOException
     */
    public void readFile(File file) throws IOException {
        try (Source fileSource = Okio.source(file)) {
            Buffer buffer = new Buffer();
            fileSource.read(buffer, 1024);
            while (fileSource.read(buffer, 1024) != -1) {
                //一次读完
                String line = buffer.readUtf8();
                System.out.println(line);
            }
        }
    }

BufferedSource

BufferedSource 是一个带有缓冲功能的 Source , 说白了BufferedSource 其实就是内置了一个 Buffer

上面的代码就可以改成:

    /**
     * 读取文件中的文本
     * @param file
     * @throws IOException
     */
    public void readFile(File file) throws IOException {
        try (Source fileSource = Okio.source(file)) {
            BufferedSource bufferedSource = Okio.buffer(fileSource);
            while (true) {
                String line = bufferedSource.readUtf8Line();
                if (line == null) break;
                System.out.println(line);
            }
        }
    }

readUtf8Line() API读取所有数据,直到下一行分隔符\n、\r\n或文件结尾。它以字符串形式返回该数据,省略结尾的分隔符。当遇到空行时,该方法将返回一个空字符串。如果没有更多的数据可读取,它将返回null

所以我们可以进一步优化代码如下:

   /**
     * 读取文件中的文本
     *
     * @param file
     * @throws IOException
     */
    public void readFile(File file) throws IOException {
        try (Source fileSource = Okio.source(file)) {
            BufferedSource bufferedSource = Okio.buffer(fileSource);
            String line;
            while ((line = bufferedSource.readUtf8Line()) != null) {
                System.out.println(line);
            }
        }
    }

所以我们也可以优化成

 /**
     * 读取文件中的文本
     *
     * @param file
     * @throws IOException
     */
    public void readFile(File file) throws IOException {
        try (Source fileSource = Okio.source(file); BufferedSource bufferedSource = Okio.buffer(fileSource)) {
            String line = bufferedSource.readUtf8();
            System.out.println(line);
        }
    }

最后我们可以封装一个方法来读取文本文件

   /**
     * 读取文件中的文本
     *
     * @param file
     * @throws IOException
     */
    public String readFile(File file) throws IOException {
        try (Source fileSource = Okio.source(file); BufferedSource bufferedSource = Okio.buffer(fileSource)) {
            return bufferedSource.readUtf8();
        }
    }

甚至可以更近一步,再简介一下:

 /**
     * 读取文件中的文本
     *
     * @param file
     * @throws IOException
     */
    public String readFile(File file) throws IOException {
        try (BufferedSource bufferedSource = Okio.buffer(Okio.source(file))) {
            return bufferedSource.readUtf8();
        }
    }

kotlin 版本如下:


    @Throws(IOException::class)
    fun readFile(file: File): String? {
        file.source().buffer().use { bufferedSource ->
            return bufferedSource.readUtf8()
        }
    }

是不是很简洁。

写文件 Sink

如果文件不存在,会自动创建文件

   /**
     * 把文本写入文件
     * @param file
     * @throws IOException
     */
    public void writeFile(String content, File file) throws IOException {
        try (Sink sink = Okio.sink(file); BufferedSink bufferedSink = Okio.buffer(sink)) {
            bufferedSink.write(content.getBytes()); //写字节
        }
    }

除此之外,还有其他写方法:

bufferedSink.write(byte[] bytes)
bufferedSink.writeUtf8(String string)
bufferedSink.writeAll(Source source)
bufferedSink.write(ByteString byteString)

综合演练1:文本读写

我们来实现一个读文本,然后再写文本的代码

public class Test {

    public static void main(String[] args) {
        Test test = new Test();
        try {
            //从文件读取文本
            String string = test.readFile(new File("/Users/xmly/workspace/web1/src/main/aa.txt"));
            //写文本到文件
            test.writeFile(string, new File("/Users/xmly/workspace/web1/src/main/aa1.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取文件中的文本
     *
     * @param file
     * @throws IOException
     */
    public String readFile(File file) throws IOException {
        try (BufferedSource bufferedSource = Okio.buffer(Okio.source(file))) {
            return bufferedSource.readUtf8();
        }
    }

    /**
     * 把文本写入文件
     *
     * @param file
     * @throws IOException
     */
    public void writeFile(String content, File file) throws IOException {
        try (Sink sink = Okio.sink(file); BufferedSink bufferedSink = Okio.buffer(sink)) {
            bufferedSink.write(content.getBytes());
        }
    }
}

综合演练2:文件复制

public class Test {

    public static void main(String[] args) {
        Test test = new Test();
        try {
            //从文件读取文本
            File file1 = new File("/Users/xmly/Desktop/1234.jpeg");
            File file2 = new File("/Users/xmly/workspace/web1/src/main/aa1.jpeg");
            test.copyFile(file1, file2);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 复制文件
     *
     * @param file1
     * @param file2
     * @throws IOException
     */
    public void copyFile(File file1, File file2) throws IOException {
        try (BufferedSource bufferedSource = Okio.buffer(Okio.source(file1)); BufferedSink bufferedSink = Okio.buffer(Okio.sink(file2))) {
            bufferedSink.writeAll(bufferedSource);
        }
    }
}

相比java IO , Okio 简直是神器,太简洁,太牛B了

上一篇:第八天 2021.08.26


下一篇:java的throw和throws异常区别