Sguotao.top /Kotlin-2018…

IO stream is a very important part of Java, common data transfer, file upload and download are inseparable from it. So how does Kotlin’s IO compare to Java’s IO?

In Java IO

IO in Java can be divided into byte stream and character stream according to the way of processing data, and can be divided into input stream and output stream according to the different transmission direction. Let’s start with a Java IO framework.

In Java, we need to pay attention to the exception handling and the flow closing operation, otherwise it may cause memory overflow. For example, using BufferedReader to read the build.gradle file in your project directory.

public static void main(String[] args) {
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new FileReader(new File("build.gradle")));
            String line;
            while((line = bufferedReader.readLine()) ! =null) { System.out.println(line); }}catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bufferedReader.close();
            } catch(IOException e) { e.printStackTrace(); }}}Copy the code

In the Kotlin IO

Gradle file with BufferedReader, and then to summarize the IO in Kotlin.

fun main(args: Array<String>) {
    val file = File("build.gradle")
    val bufferedReader = BufferedReader(FileReader(file))
    var line: String

    try {
        while (true) { line = bufferedReader.readLine() ? :break
            println(line)
        }
    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        try {
            bufferedReader.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}
Copy the code

This seems to be no different from Java writing, so where does Kotlin stand out? Fortunately, Kotlin encapsulates many higher-order functions. Here is a version that uses higher-order functions.

fun main(args: Array<String>) {
    val file = File("build.gradle")
    BufferedReader(FileReader(file)).use {
        var line: String
        while (true) { line = it.readLine() ? :break
            println(line)
        }
    }
}
Copy the code

The code has been streamlined, leaving out some exception catching, because such template code kotlin has already wrapped, so you don’t have to worry about forgetting to close the convection anymore. For small files, there is a simpler way to write:

fun main(args: Array<String>) {
    File("build.gradle").readLines().forEach(::println)
}
Copy the code

Kotlin extension function for IO

So what extension functions are available in Kotlin? What are the effects of these extension functions? Kotlin does not duplicate the IO streams that already exist in Java. Instead, Kotlin extends the byte streams and character streams that are often used. Here we can classify these extension functions into the following categories by differentiating extension objects.

BufferedReader (Charset: charset) is a bufferedReader whose extended object is an InputStream. Then we can call this method on InputStream and its subclasses, for example:

    val inputStream: InputStream = FileInputStream("build.gradle")
    inputStream.bufferedReader().forEachLine { line ->
        println(line)
    }
Copy the code

Kotlin’s extension of the byte stream

Kotlin’s extensions to the byte stream are mainly in byteStreamkt.class, as described below:

The serial number Extension function name Extended object describe
1 buffered((bufferSize: Int) InputStream Wrap the byte input stream, resulting in a byte input stream BufferedInputStream with a buffer of 8 x 1024 bytes by default.
2 bufferedReader(charset: Charset) InputStream Wrapping the byte input stream produces a BufferedReader character input stream, the default character encoding is UTF-8.
3 copyTo(out: OutputStream, bufferSize: Int ) InputStream Copy the byte input stream to the given output stream and return the number of bytes copied. The default buffer size is 8*1024 bytes. Note that both streams require manual close.
4 readBytes(estimatedSize: Int) InputStream Reads the byte input stream into a byte array of a size not larger than 8*1024.
5 reader(charset: Charset) InputStream Wrapping a byte input stream yields a character input stream, InputStreamReader, whose default character encoding is UTF-8.
6 buffered(bufferSize: Int) OutputStream Wrapping the byte input stream yields a byte output stream BufferedOutputStream with a buffer, the default size of which is 8*1024 bytes.
7 bufferedWriter(charset: Charset) OutputStream Wrapping the byte output stream yields a character output stream BufferedWriter with a buffered character encoding of UTF-8 by default.
8 writer(charset: Charset) OutputStream Wrapping the byte output stream yields a character output stream OutputStreamWriter, whose default character encoding is UTF-8.
9 inputStream() ByteArray Creates a byte input stream ByteArrayInputStream for the given byte array to read from.
10 inputStream(offset: Int, length: Int) ByteArray Creates a byte input stream ByteArrayInputStream for the given byte array to read from, where offset is the read position, which is the offset from the start position, and Length is the read length.
11 byteInputStream(charset: Charset) String Creates a byte input stream ByteArrayInputStream for the given string, encoded utF-8 by default.

Kotlin’s extension to character streams

Kotlin’s extensions to character streams are mainly in TextStreamkt.class, and we’ll look at each of these extension functions one by one:

The serial number Extension function name Extended object describe
1 buffered(bufferSize: Int) Reader Wrapping the character input stream produces a character input stream BufferedReader with a default size of 8*1024 bytes.
2 copyTo(out: Writer, bufferSize: Int) Reader Copies a character input stream to a given character output stream, returning the number of characters copied, with a default buffer size of 8*1024 bytes. Note that both streams require manual close.
3 forEachLine(action: (String) -> Unit) Reader Each line read by the character input stream Reader is iterated over, calling the incoming function on each line, and closing the stream when it is finished. This function takes a String argument and returns no value.
4 readLines() Reader Each row of the array read by the character input stream is stored in a List, and the List is returned after reading. Do not use this function to read large files, otherwise it will cause memory overflow.
5 readText() Reader Returns what the character input stream reads as a string. The stream needs to be closed manually.
6 useLines(block: (Sequence) -> T) Reader Store the contents of the character input stream Reader in a sequence of characters, execute the incoming lambda expression on the sequence of characters, and close the stream after processing, using the return value of the lambda expression as the return value of the function.
7 buffered(bufferSize: Int) Writer The character output stream is wrapped to obtain a character output stream BufferedWriter with a buffer. The default size of the buffer is 8*1024 bytes.
8 readBytes() URL Read the content returned from the URL into a byte array. The default size of the byte array is 8 x 1024 bytes. Do not read large files; otherwise, memory overflow may occur.
9 readText(charset: Charset) URL The content returned from the URL is returned as a string. The default character encoding is UTF-8. Do not read large files; otherwise, memory overflow may occur.
10 reader() String Creates a character input stream, StringReader, for the given string.

Kotlin’s extension to File

Kotlin’s extensions to File are mainly in filekt.class. Here are some of the extension functions:

The serial number Extension function Extended object describe
1 appendBytes(array: ByteArray) File Appends to a file the size of the specified byte array.
2 appendText(text: String, charset: Charset File Appends the specified content to the file. The default character encoding is UTF-8.
3 bufferedReader(charset: Charset, bufferSize: Int ) File Wrap the file and get a character input stream with a buffer. The default encoding of the input stream is UTF-8 and the default buffer size is 8*1024 bytes.
4 bufferedWriter(charset: Charset, bufferSize: Int) File Wrap the file and get a character output stream with a buffer. The default encoding of the output stream is UTF-8 and the default buffer size is 8*1024 bytes.
5 copyRecursively(target: File,overwrite: Boolean, onError: (File, IOException)) File To recursively copy a file, this function takes three arguments, target, the destination address of the copy file, whether to overwrite, the default value is false. The function returns true if replication is complete or interrupted. If the specified destination address does not have a file, a file is created. If File refers to a single File, copy the File directly to the target directory. If File points to a directory, recursively copy all subdirectories and files in the directory to the target directory. If the File specified by target already exists, overwrite is used to control whether the File is overwritten. Some attributes of files, such as creation date, read and write permissions, are not saved when copied. Accepts an expression to handle an exception, which is thrown by default.It is important to note that partial replication may occur if replication fails.
6 copyTo(target: File, overwrite: Boolean, bufferSize: Int ) File Copy the file to the specified path. If the specified path does not exist, the file is created. If there is overwrite control based on the overwrite parameter; If target points to a directory and overwrite is set to true, the file will be copied only if the directory is empty. If File points to a directory, calling this method creates only the directory specified by target and does not copy the contents of the directory. Finally, some attribute information of the file, such as creation date, read and write permission, is not saved when copying.
7 deleteRecursively() File Delete files recursively. If the file points to a directory, delete the contents of the directory recursively.It is important to note that partial deletion may occur if recursive deletion fails.
8 endsWith(other: File) File Check whether the file path ends in the path of the given file other.
9 endsWith(other: String) File Checks whether the file path is in the same root directory as the path pointed to by the given string, and the file path ends in a string.
10 forEachBlock(action: (buffer: ByteArray, bytesRead: Int) -> Unit) File This function takes an expression that takes two arguments, a byte array buffer and an Int bytesRead. The expression returns no value. The function reads the file at the length of the byte array (default size 4096 bytes) and calls the expression passed in once for each byte of the array’s contents. For example, if the file size is 7409 bytes, the expression is called twice, first when 4096 bytes are read, and then again when the remaining 3313 bytes are read.
11 forEachBlock(blockSize: Int, action: (buffer: ByteArray, bytesRead: Int) -> Unit) File This function does the same thing as the 10th function, except that you can specify the size of the byte array buffer.
12 forEachLine(charset: Charset = Charsets.UTF_8, action: (line: String) -> Unit) File This function takes a character encoding argument, charset, and an expression that takes a String argument and returns no value. The function reads the file line by line according to the specified character encoding (utF-8 by default), and calls the expression passed in once for each line read.This function can be used to read large files.
13 inputStream() File Wrapping the file gives you a byte InputStream, InputStream.
14 normalize() File Removes the file contained in the file path. And parse.. For example, the File path is File(“/foo/./bar/gav/.. /baaz”) the result of normalize() is File(“/foo/bar/baaz”).
15 outputStream() File The file is wrapped, resulting in a byte OutputStream OutputStream.
16 printWriter(charset: Charset) File Wrap the file to get a character output stream PrintWriter. The default character encoding is UTF-8.
17 readBytes() File Reads the contents of the file into a byte array and returns the byte array. This function does not recommend reading large files, otherwise it will cause memory overflow. The function internally limits the size of byte arrays to no more than 2GB.
18 reader(charset: Charset) File Wrap the file to get a character input stream, InputStreamReader. The default character encoding is UTF-8.
19 readLines(charset: Charset) File Reads a file into a LIst, line by line, according to the specified character encoding, and returns the LIst. The default character encoding is UTF-8.This method does not recommend reading large files, which may cause memory overflow.
20 readText(charset: Charset) File Reads the entire file according to the specified character encoding, and returns the read as a String. ** This method does not recommend reading large files, which may cause memory overflow. The ** function internally limits the file size to 2GB.
21 relativeTo(base: File) File Computes the relative path to the specified file base. The base argument is treated as a file directory, and an empty path is returned if the file has the same path as base. If the file has a different root path than the base file, IllegalArgumentException is thrown.
22 File.relativeToOrNull(base: File) File Computes the relative path to the specified file base, returning an empty path if the file path is the same as base, or null if the file path has a different root path from base.
23 relativeToOrSelf(base: File) File Computes the relative path to the specified file base, returns an empty path if the file path is the same as base, or returns the file itself if the file path has a different root path from base.
24 resolve(relative: File) File Add the path to the specified file relatived to the directory of the current file. Relative returns the relative file itself if it has a root path, otherwise returns the added file path. Resolve (File(“gav”)) will result in File(“/foo/bar/gav”).
25 resolve(relative: String) File Adds the specified path relative to the directory of the current file.
26 resolveSibling(relative: File) File Add the path to the specified file relative to the directory above the current file. Return relative itself if the file relative has a root path, otherwise return the added file path. The result of resolve(“gav”) will be File(“/foo/bar/gav”).
27 resolveSibling(relative: String) File Adds the specified path relative to the directory above the current file directory.
28 startsWith(other: File) File Check whether the current file has the same root directory as the given file other, and whether the current file path starts with the specified file path.
29 startsWith(other: String) File Determines whether the current file has the same root directory as the following path, and whether the current file path begins with the given path.
30 toRelativeString(base: File) File Computes the relative path of the current file to the specified file base, returns an empty string if the current file path is the same as the base path, and throws an IllegalArgumentException if the current file has a different root path from Base.
31 useLines(charset: Charset = Charsets.UTF_8, block: (Sequence) -> T) File This function takes two arguments: a character encoding charset and an expression. The default character encoding is UTF-8. The expression takes a sequence of characters and returns a generic, with the return value of the expression as the return value of the function. This function is similar to forEachline() except that it returns a sequence of characters and closes the stream when it returns a sequence of characters.
32 walk(direction: FileWalkDirection = FileWalkDirection.TOP_DOWN) File The depth-first command traverses the current directory and contents in the directory in the specified sequence (top-down or bottom-up). By default, the depth-first command traverses the current directory and contents in the directory in the specified sequence (top-down or bottom-up). A file access sequence is obtained.
33 walkBottomUp() File In accordance with theFrom the bottom upThis function uses depth-first traversal to obtain a file access sequence, that is, the sequence of accessing files first, then accessing file directories.
34 walkTopDown() File In accordance with theThe top-downThis function uses depth-first traversal to obtain a file access sequence, that is, the file directory is accessed first, then the file access sequence.
35 writeBytes(array: ByteArray) File Writes the contents of the specified byte array to a file, overwriting if the file already exists.
36 writer(charset: Charset = Charsets.UTF_8) File Wrapper the file, resulting in a character output stream OutputStreamWriter, the default character encoding is UTF-8.
37 writeText(text: String, charset: Charset = Charsets.UTF_8) File Writes the specified string contents to a file, according to the default UTF-8 encoding, or overwrites if the file already exists.

Kotlin other IO extensions

IO streams in Java inherit the Closeable interface. In kotlin. IO, closeablekt. class, there is an extension function for use:

public inline fun 
        T.use(block: (T) -> R): R {
    var exception: Throwable? = null
    try {
        return block(this)}catch (e: Throwable) {
        exception = e
        throw e
    } finally {
        when {
            apiVersionIsAtLeast(1.1.0) - >this.closeFinally(exception)
            this= =null -> {}
            exception == null -> close()
            else ->
                try {
                    close()
                } catch (closeException: Throwable) {
                    // cause.addSuppressed(closeException) // ignored here}}}}Copy the code

The use function encapsulates the try… catch… Finally template code, which is why, in Kotlin, there is no convection shutdown when using use on IO streams, because Kotlin already encapsulates it.

In Kotlin. IO, consolekt. class encapsulates terminal IO operations such as system.out.print. In Kotlin, print and println can be directly printed on the command line.

Learning materials

  1. Kotlin Bootcamp for Programmers
  2. Kotlin Koans