stdlib: rearrange IO functions
This commit is contained in:
committed by
Ilya Ryzhenkov
parent
3e7b0be68d
commit
1a4c11cb98
@@ -1,31 +0,0 @@
|
||||
package kotlin
|
||||
|
||||
import java.io.Closeable
|
||||
|
||||
/** Uses the given resource then closes it down correctly whether an exception is thrown or not */
|
||||
public inline fun <T : Closeable, R> T.use(block: (T) -> R): R {
|
||||
var closed = false
|
||||
try {
|
||||
return block(this)
|
||||
} catch (e: Exception) {
|
||||
closed = true
|
||||
try {
|
||||
this.close()
|
||||
} catch (closeException: Exception) {
|
||||
// eat the closeException as we are already throwing the original cause
|
||||
// and we don't want to mask the real exception
|
||||
|
||||
// TODO on Java 7 we should call
|
||||
// e.addSuppressed(closeException)
|
||||
// to work like try-with-resources
|
||||
// http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html#suppressed-exceptions
|
||||
}
|
||||
throw e
|
||||
} finally {
|
||||
if (!closed) {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
package kotlin.io
|
||||
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.io.BufferedReader
|
||||
|
||||
/**
|
||||
* Returns the default buffer size when working with buffered streams
|
||||
*/
|
||||
public val defaultBufferSize: Int = 64 * 1024
|
||||
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Any?) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Int) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Long) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Byte) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Short) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Char) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Boolean) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Float) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Double) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: CharArray) {
|
||||
System.out.print(message)
|
||||
}
|
||||
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Any?) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Int) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Long) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Byte) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Short) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Char) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Boolean) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Float) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Double) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: CharArray) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints a newline t[[System.out]] */
|
||||
public fun println() {
|
||||
System.out.println()
|
||||
}
|
||||
|
||||
// Since System.in can change its value on the course of program running,
|
||||
// we should always delegate to current value and cannot just pass it to InputStreamReader constructor.
|
||||
// We could use "by" implementation, but we can only use "by" with traits and InputStream is abstract class.
|
||||
private val stdin: BufferedReader = BufferedReader(InputStreamReader(object : InputStream() {
|
||||
public override fun read(): Int {
|
||||
return System.`in`.read()
|
||||
}
|
||||
|
||||
public override fun reset() {
|
||||
System.`in`.reset()
|
||||
}
|
||||
|
||||
public override fun read(b: ByteArray): Int {
|
||||
return System.`in`.read(b)
|
||||
}
|
||||
|
||||
public override fun close() {
|
||||
System.`in`.close()
|
||||
}
|
||||
|
||||
public override fun mark(readlimit: Int) {
|
||||
System.`in`.mark(readlimit)
|
||||
}
|
||||
|
||||
public override fun skip(n: Long): Long {
|
||||
return System.`in`.skip(n)
|
||||
}
|
||||
|
||||
public override fun available(): Int {
|
||||
return System.`in`.available()
|
||||
}
|
||||
|
||||
public override fun markSupported(): Boolean {
|
||||
return System.`in`.markSupported()
|
||||
}
|
||||
|
||||
public override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||
return System.`in`.read(b, off, len)
|
||||
}
|
||||
}))
|
||||
|
||||
/** Reads a line of input from [[System.in]] */
|
||||
public fun readLine(): String? = stdin.readLine()
|
||||
@@ -78,76 +78,6 @@ public fun File.relativePath(descendant: File): String {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [[FileReader]] for this file
|
||||
*/
|
||||
public fun File.reader(): FileReader = FileReader(this)
|
||||
|
||||
/**
|
||||
* Reads the entire content of the file as bytes
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun File.readBytes(): ByteArray {
|
||||
return FileInputStream(this).use { it.readBytes(length().toInt()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the bytes as the contents of the file
|
||||
*/
|
||||
public fun File.writeBytes(data: ByteArray): Unit {
|
||||
return FileOutputStream(this).use { it.write(data) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends bytes to the contents of the file.
|
||||
*/
|
||||
public fun File.appendBytes(data: ByteArray): Unit {
|
||||
return FileOutputStream(this, true).use { it.write(data) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entire content of the file as a String using specified charset.
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun File.readText(charset: String): String = readBytes().toString(charset)
|
||||
|
||||
/**
|
||||
* Reads the entire content of the file as a String using UTF-8 or specified charset.
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun File.readText(charset: Charset = Charsets.UTF_8): String = readBytes().toString(charset)
|
||||
|
||||
/**
|
||||
* Writes the text as the contents of the file using specified charset.
|
||||
*/
|
||||
public fun File.writeText(text: String, charset: String): Unit {
|
||||
writeBytes(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the text as the contents of the file using UTF-8 or specified charset.
|
||||
*/
|
||||
public fun File.writeText(text: String, charset: Charset = Charsets.UTF_8): Unit {
|
||||
writeBytes(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends text to the contents of the file using UTF-8 or specified charset.
|
||||
*/
|
||||
public fun File.appendText(text: String, charset: Charset = Charsets.UTF_8): Unit {
|
||||
appendBytes(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends text to the contents of the file using specified charset.
|
||||
*/
|
||||
public fun File.appendText(text: String, charset: String): Unit {
|
||||
appendBytes(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies this file to the given output file, returning the number of bytes copied
|
||||
*/
|
||||
@@ -162,69 +92,6 @@ public fun File.copyTo(file: File, bufferSize: Int = defaultBufferSize): Long {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads file by byte blocks and calls closure for each block read. Block size depends on implementation but never less than 512.
|
||||
* This functions passes byte array and amount of bytes in this buffer to the closure function.
|
||||
*
|
||||
* You can use this function for huge files
|
||||
*/
|
||||
public fun File.forEachBlock(closure: (ByteArray, Int) -> Unit): Unit {
|
||||
val arr = ByteArray(4096)
|
||||
val fis = FileInputStream(this)
|
||||
|
||||
try {
|
||||
do {
|
||||
val size = fis.read(arr)
|
||||
if (size == -1) {
|
||||
break
|
||||
} else if (size > 0) {
|
||||
closure(arr, size)
|
||||
}
|
||||
} while (true)
|
||||
} finally {
|
||||
fis.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads file line by line using specified [charset]. Default charset is UTF-8.
|
||||
*
|
||||
* You may use this function on huge files
|
||||
*/
|
||||
public fun File.forEachLine(charset: Charset = Charsets.UTF_8, closure: (line: String) -> Unit): Unit {
|
||||
val reader = BufferedReader(InputStreamReader(FileInputStream(this), charset))
|
||||
try {
|
||||
reader.forEachLine(closure)
|
||||
} finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads file line by line using the specified [charset].
|
||||
*
|
||||
* You may use this function on huge files
|
||||
*/
|
||||
public fun File.forEachLine(charset: String, closure: (line: String) -> Unit): Unit = forEachLine(Charset.forName(charset), closure)
|
||||
|
||||
/**
|
||||
* Reads file content into list of lines using specified [charset]
|
||||
*
|
||||
* Do not use this function for huge files.
|
||||
*/
|
||||
public fun File.readLines(charset: String): List<String> = readLines(Charset.forName(charset))
|
||||
|
||||
/**
|
||||
* Reads file content as strings list. By default uses UTF-8 charset.
|
||||
*
|
||||
* Do not use this function for huge files.
|
||||
*/
|
||||
public fun File.readLines(charset: Charset = Charsets.UTF_8): List<String> {
|
||||
val result = ArrayList<String>()
|
||||
forEachLine(charset) { result.add(it); }
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of files and directories in the directory that satisfy the specified filter.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package kotlin.io
|
||||
|
||||
import java.io.*
|
||||
import java.nio.charset.Charset
|
||||
import java.nio.charset.CharsetDecoder
|
||||
import java.nio.charset.CharsetEncoder
|
||||
|
||||
/** Returns an [Iterator] of bytes over an input stream */
|
||||
public fun InputStream.iterator(): ByteIterator =
|
||||
object: ByteIterator() {
|
||||
override fun hasNext(): Boolean = available() > 0
|
||||
|
||||
public override fun nextByte(): Byte = read().toByte()
|
||||
}
|
||||
|
||||
/** Creates a buffered input stream */
|
||||
public fun InputStream.buffered(bufferSize: Int = defaultBufferSize): InputStream
|
||||
= if (this is BufferedInputStream)
|
||||
this
|
||||
else
|
||||
BufferedInputStream(this, bufferSize)
|
||||
|
||||
/** Creates a reader on an input stream using UTF-8 or specified charset. */
|
||||
public fun InputStream.reader(charset: Charset = Charsets.UTF_8): InputStreamReader = InputStreamReader(this, charset)
|
||||
|
||||
/** Creates a reader on an input stream using specified *charset* */
|
||||
public fun InputStream.reader(charset: String): InputStreamReader = InputStreamReader(this, charset)
|
||||
|
||||
/** Creates a reader on an input stream using specified *decoder* */
|
||||
public fun InputStream.reader(decoder: CharsetDecoder): InputStreamReader = InputStreamReader(this, decoder)
|
||||
|
||||
/** Creates a buffered output stream */
|
||||
public fun OutputStream.buffered(bufferSize: Int = defaultBufferSize): BufferedOutputStream
|
||||
= if (this is BufferedOutputStream) this else BufferedOutputStream(this, bufferSize)
|
||||
|
||||
/** Creates a writer on an output stream using UTF-8 or specified charset. */
|
||||
public fun OutputStream.writer(charset: Charset = Charsets.UTF_8): OutputStreamWriter = OutputStreamWriter(this, charset)
|
||||
|
||||
/** Creates a writer on an output stream using specified *charset* */
|
||||
public fun OutputStream.writer(charset: String): OutputStreamWriter = OutputStreamWriter(this, charset)
|
||||
|
||||
/** Creates a writer on an output stream using specified *encoder* */
|
||||
public fun OutputStream.writer(encoder: CharsetEncoder): OutputStreamWriter = OutputStreamWriter(this, encoder)
|
||||
|
||||
/**
|
||||
* Copies this stream to the given output stream, returning the number of bytes copied
|
||||
*
|
||||
* **Note** it is the callers responsibility to close both of these resources
|
||||
*/
|
||||
public fun InputStream.copyTo(out: OutputStream, bufferSize: Int = defaultBufferSize): Long {
|
||||
var bytesCopied: Long = 0
|
||||
val buffer = ByteArray(bufferSize)
|
||||
var bytes = read(buffer)
|
||||
while (bytes >= 0) {
|
||||
out.write(buffer, 0, bytes)
|
||||
bytesCopied += bytes
|
||||
bytes = read(buffer)
|
||||
}
|
||||
return bytesCopied
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads this stream completely into a byte array
|
||||
*
|
||||
* **Note** it is the callers responsibility to close this resource
|
||||
*/
|
||||
public fun InputStream.readBytes(estimatedSize: Int = defaultBufferSize): ByteArray {
|
||||
val buffer = ByteArrayOutputStream(estimatedSize)
|
||||
this.copyTo(buffer)
|
||||
return buffer.toByteArray()
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
package kotlin.io
|
||||
|
||||
import java.io.*
|
||||
import java.nio.charset.*
|
||||
import java.util.NoSuchElementException
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* Returns the default buffer size when working with buffered streams
|
||||
*/
|
||||
public val defaultBufferSize: Int = 64 * 1024
|
||||
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Any?) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Int) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Long) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Byte) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Short) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Char) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Boolean) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Float) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: Double) {
|
||||
System.out.print(message)
|
||||
}
|
||||
/** Prints the given message to [[System.out]] */
|
||||
public fun print(message: CharArray) {
|
||||
System.out.print(message)
|
||||
}
|
||||
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Any?) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Int) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Long) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Byte) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Short) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Char) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Boolean) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Float) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: Double) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints the given message and newline to [[System.out]] */
|
||||
public fun println(message: CharArray) {
|
||||
System.out.println(message)
|
||||
}
|
||||
/** Prints a newline t[[System.out]] */
|
||||
public fun println() {
|
||||
System.out.println()
|
||||
}
|
||||
|
||||
// Since System.in can change its value on the course of program running,
|
||||
// we should always delegate to current value and cannot just pass it to InputStreamReader constructor.
|
||||
// We could use "by" implementation, but we can only use "by" with traits and InputStream is abstract class.
|
||||
private val stdin: BufferedReader = BufferedReader(InputStreamReader(object : InputStream() {
|
||||
public override fun read(): Int {
|
||||
return System.`in`.read()
|
||||
}
|
||||
|
||||
public override fun reset() {
|
||||
System.`in`.reset()
|
||||
}
|
||||
|
||||
public override fun read(b: ByteArray): Int {
|
||||
return System.`in`.read(b)
|
||||
}
|
||||
|
||||
public override fun close() {
|
||||
System.`in`.close()
|
||||
}
|
||||
|
||||
public override fun mark(readlimit: Int) {
|
||||
System.`in`.mark(readlimit)
|
||||
}
|
||||
|
||||
public override fun skip(n: Long): Long {
|
||||
return System.`in`.skip(n)
|
||||
}
|
||||
|
||||
public override fun available(): Int {
|
||||
return System.`in`.available()
|
||||
}
|
||||
|
||||
public override fun markSupported(): Boolean {
|
||||
return System.`in`.markSupported()
|
||||
}
|
||||
|
||||
public override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||
return System.`in`.read(b, off, len)
|
||||
}
|
||||
}))
|
||||
|
||||
/** Reads a line of input from [[System.in]] */
|
||||
public fun readLine(): String? = stdin.readLine()
|
||||
|
||||
/** Returns an [Iterator] of bytes over an input stream */
|
||||
public fun InputStream.iterator(): ByteIterator =
|
||||
object: ByteIterator() {
|
||||
override fun hasNext(): Boolean = available() > 0
|
||||
|
||||
public override fun nextByte(): Byte = read().toByte()
|
||||
}
|
||||
|
||||
/** Creates a buffered input stream */
|
||||
public fun InputStream.buffered(bufferSize: Int = defaultBufferSize): InputStream
|
||||
= if (this is BufferedInputStream)
|
||||
this
|
||||
else
|
||||
BufferedInputStream(this, bufferSize)
|
||||
|
||||
/** Creates a reader on an input stream using UTF-8 or specified charset. */
|
||||
public fun InputStream.reader(charset: Charset = Charsets.UTF_8): InputStreamReader = InputStreamReader(this, charset)
|
||||
|
||||
/** Creates a reader on an input stream using specified *charset* */
|
||||
public fun InputStream.reader(charset: String): InputStreamReader = InputStreamReader(this, charset)
|
||||
|
||||
/** Creates a reader on an input stream using specified *decoder* */
|
||||
public fun InputStream.reader(decoder: CharsetDecoder): InputStreamReader = InputStreamReader(this, decoder)
|
||||
|
||||
|
||||
/** Creates a buffered output stream */
|
||||
public fun OutputStream.buffered(bufferSize: Int = defaultBufferSize): BufferedOutputStream
|
||||
= if (this is BufferedOutputStream) this else BufferedOutputStream(this, bufferSize)
|
||||
|
||||
/** Creates a writer on an output stream using UTF-8 or specified charset. */
|
||||
public fun OutputStream.writer(charset: Charset = Charsets.UTF_8): OutputStreamWriter = OutputStreamWriter(this, charset)
|
||||
|
||||
/** Creates a writer on an output stream using specified *charset* */
|
||||
public fun OutputStream.writer(charset: String): OutputStreamWriter = OutputStreamWriter(this, charset)
|
||||
|
||||
/** Creates a writer on an output stream using specified *encoder* */
|
||||
public fun OutputStream.writer(encoder: CharsetEncoder): OutputStreamWriter = OutputStreamWriter(this, encoder)
|
||||
|
||||
|
||||
/** Creates a buffered reader, or returns self if Reader is already buffered */
|
||||
public fun Reader.buffered(bufferSize: Int = defaultBufferSize): BufferedReader
|
||||
= if (this is BufferedReader) this else BufferedReader(this, bufferSize)
|
||||
|
||||
/** Creates a buffered writer, or returns self if Writer is already buffered */
|
||||
public fun Writer.buffered(bufferSize: Int = defaultBufferSize): BufferedWriter
|
||||
= if (this is BufferedWriter) this else BufferedWriter(this, bufferSize)
|
||||
|
||||
/**
|
||||
* Iterates through each line of this reader then closing the [[Reader]] when its completed
|
||||
*/
|
||||
public fun Reader.forEachLine(block: (String) -> Unit): Unit = useLines { lines -> lines.forEach(block) }
|
||||
|
||||
public inline fun <T> Reader.useLines(block: (Stream<String>) -> T): T =
|
||||
this.buffered().use { block(it.lines()) }
|
||||
|
||||
/**
|
||||
* Returns an iterator over each line.
|
||||
* <b>Note</b> the caller must close the underlying <code>BufferedReader</code>
|
||||
* when the iteration is finished; as the user may not complete the iteration loop (e.g. using a method like find() or any() on the iterator
|
||||
* may terminate the iteration early.
|
||||
* <br>
|
||||
* We suggest you try the method useLines() instead which closes the stream when the processing is complete.
|
||||
*/
|
||||
public fun BufferedReader.lines(): Stream<String> = LinesStream(this)
|
||||
|
||||
deprecated("Use lines() function which returns Stream<String>")
|
||||
public fun BufferedReader.lineIterator(): Iterator<String> = lines().iterator()
|
||||
|
||||
private class LinesStream(private val reader: BufferedReader) : Stream<String> {
|
||||
override fun iterator(): Iterator<String> {
|
||||
return object : Iterator<String> {
|
||||
private var nextValue: String? = null
|
||||
private var done = false
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (nextValue == null && !done) {
|
||||
nextValue = reader.readLine()
|
||||
if (nextValue == null) done = true
|
||||
}
|
||||
return nextValue != null
|
||||
}
|
||||
|
||||
public override fun next(): String {
|
||||
if (!hasNext()) {
|
||||
throw NoSuchElementException()
|
||||
}
|
||||
val answer = nextValue
|
||||
nextValue = null
|
||||
return answer!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads this stream completely into a byte array
|
||||
*
|
||||
* **Note** it is the callers responsibility to close this resource
|
||||
*/
|
||||
public fun InputStream.readBytes(estimatedSize: Int = defaultBufferSize): ByteArray {
|
||||
val buffer = ByteArrayOutputStream(estimatedSize)
|
||||
this.copyTo(buffer)
|
||||
return buffer.toByteArray()
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads this reader completely as a String
|
||||
*
|
||||
* **Note** it is the callers responsibility to close this resource
|
||||
*/
|
||||
public fun Reader.readText(): String {
|
||||
val buffer = StringWriter()
|
||||
copyTo(buffer)
|
||||
return buffer.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies this stream to the given output stream, returning the number of bytes copied
|
||||
*
|
||||
* **Note** it is the callers responsibility to close both of these resources
|
||||
*/
|
||||
public fun InputStream.copyTo(out: OutputStream, bufferSize: Int = defaultBufferSize): Long {
|
||||
var bytesCopied: Long = 0
|
||||
val buffer = ByteArray(bufferSize)
|
||||
var bytes = read(buffer)
|
||||
while (bytes >= 0) {
|
||||
out.write(buffer, 0, bytes)
|
||||
bytesCopied += bytes
|
||||
bytes = read(buffer)
|
||||
}
|
||||
return bytesCopied
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies this reader to the given output writer, returning the number of bytes copied.
|
||||
*
|
||||
* **Note** it is the callers responsibility to close both of these resources
|
||||
*/
|
||||
public fun Reader.copyTo(out: Writer, bufferSize: Int = defaultBufferSize): Long {
|
||||
var charsCopied: Long = 0
|
||||
val buffer = CharArray(bufferSize)
|
||||
var chars = read(buffer)
|
||||
while (chars >= 0) {
|
||||
out.write(buffer, 0, chars)
|
||||
charsCopied += chars
|
||||
chars = read(buffer)
|
||||
}
|
||||
return charsCopied
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entire content of the URL as a String using specified charset.
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun URL.readText(charset: String): String = readBytes().toString(charset)
|
||||
|
||||
/**
|
||||
* Reads the entire content of the URL as a String using UTF-8 or specified charset..
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun URL.readText(charset: Charset = Charsets.UTF_8): String = readBytes().toString(charset)
|
||||
|
||||
/**
|
||||
* Reads the entire content of the URL as bytes
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun URL.readBytes(): ByteArray = this.openStream()!!.use<InputStream, ByteArray>{ it.readBytes() }
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
package kotlin.io
|
||||
|
||||
import java.io.*
|
||||
import java.nio.charset.Charset
|
||||
import java.net.URL
|
||||
import java.util.ArrayList
|
||||
import java.util.NoSuchElementException
|
||||
|
||||
/**
|
||||
* Creates a new [[FileReader]] for this file
|
||||
*/
|
||||
public fun File.reader(): FileReader = FileReader(this)
|
||||
|
||||
/**
|
||||
* Reads the entire content of the file as bytes
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun File.readBytes(): ByteArray {
|
||||
return FileInputStream(this).use { it.readBytes(length().toInt()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the bytes as the contents of the file
|
||||
*/
|
||||
public fun File.writeBytes(data: ByteArray): Unit {
|
||||
return FileOutputStream(this).use { it.write(data) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends bytes to the contents of the file.
|
||||
*/
|
||||
public fun File.appendBytes(data: ByteArray): Unit {
|
||||
return FileOutputStream(this, true).use { it.write(data) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entire content of the file as a String using specified charset.
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun File.readText(charset: String): String = readBytes().toString(charset)
|
||||
|
||||
/**
|
||||
* Reads the entire content of the file as a String using UTF-8 or specified charset.
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun File.readText(charset: Charset = Charsets.UTF_8): String = readBytes().toString(charset)
|
||||
|
||||
/**
|
||||
* Writes the text as the contents of the file using specified charset.
|
||||
*/
|
||||
public fun File.writeText(text: String, charset: String): Unit {
|
||||
writeBytes(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the text as the contents of the file using UTF-8 or specified charset.
|
||||
*/
|
||||
public fun File.writeText(text: String, charset: Charset = Charsets.UTF_8): Unit {
|
||||
writeBytes(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends text to the contents of the file using UTF-8 or specified charset.
|
||||
*/
|
||||
public fun File.appendText(text: String, charset: Charset = Charsets.UTF_8): Unit {
|
||||
appendBytes(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends text to the contents of the file using specified charset.
|
||||
*/
|
||||
public fun File.appendText(text: String, charset: String): Unit {
|
||||
appendBytes(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads file by byte blocks and calls closure for each block read. Block size depends on implementation but never less than 512.
|
||||
* This functions passes byte array and amount of bytes in this buffer to the closure function.
|
||||
*
|
||||
* You can use this function for huge files
|
||||
*/
|
||||
public fun File.forEachBlock(closure: (ByteArray, Int) -> Unit): Unit {
|
||||
val arr = ByteArray(4096)
|
||||
val fis = FileInputStream(this)
|
||||
|
||||
try {
|
||||
do {
|
||||
val size = fis.read(arr)
|
||||
if (size == -1) {
|
||||
break
|
||||
} else if (size > 0) {
|
||||
closure(arr, size)
|
||||
}
|
||||
} while (true)
|
||||
} finally {
|
||||
fis.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads file line by line using specified [charset]. Default charset is UTF-8.
|
||||
*
|
||||
* You may use this function on huge files
|
||||
*/
|
||||
public fun File.forEachLine(charset: Charset = Charsets.UTF_8, closure: (line: String) -> Unit): Unit {
|
||||
val reader = BufferedReader(InputStreamReader(FileInputStream(this), charset))
|
||||
try {
|
||||
reader.forEachLine(closure)
|
||||
} finally {
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads file line by line using the specified [charset].
|
||||
*
|
||||
* You may use this function on huge files
|
||||
*/
|
||||
public fun File.forEachLine(charset: String, closure: (line: String) -> Unit): Unit = forEachLine(Charset.forName(charset), closure)
|
||||
|
||||
/**
|
||||
* Reads file content into list of lines using specified [charset]
|
||||
*
|
||||
* Do not use this function for huge files.
|
||||
*/
|
||||
public fun File.readLines(charset: String): List<String> = readLines(Charset.forName(charset))
|
||||
|
||||
/**
|
||||
* Reads file content as strings list. By default uses UTF-8 charset.
|
||||
*
|
||||
* Do not use this function for huge files.
|
||||
*/
|
||||
public fun File.readLines(charset: Charset = Charsets.UTF_8): List<String> {
|
||||
val result = ArrayList<String>()
|
||||
forEachLine(charset) { result.add(it); }
|
||||
return result
|
||||
}
|
||||
|
||||
/** Creates a buffered reader, or returns self if Reader is already buffered */
|
||||
public fun Reader.buffered(bufferSize: Int = defaultBufferSize): BufferedReader
|
||||
= if (this is BufferedReader) this else BufferedReader(this, bufferSize)
|
||||
|
||||
/** Creates a buffered writer, or returns self if Writer is already buffered */
|
||||
public fun Writer.buffered(bufferSize: Int = defaultBufferSize): BufferedWriter
|
||||
= if (this is BufferedWriter) this else BufferedWriter(this, bufferSize)
|
||||
|
||||
/**
|
||||
* Iterates through each line of this reader then closing the [[Reader]] when its completed
|
||||
*/
|
||||
public fun Reader.forEachLine(block: (String) -> Unit): Unit = useLines { lines -> lines.forEach(block) }
|
||||
|
||||
public inline fun <T> Reader.useLines(block: (Stream<String>) -> T): T =
|
||||
this.buffered().use { block(it.lines()) }
|
||||
|
||||
/**
|
||||
* Returns an iterator over each line.
|
||||
* <b>Note</b> the caller must close the underlying <code>BufferedReader</code>
|
||||
* when the iteration is finished; as the user may not complete the iteration loop (e.g. using a method like find() or any() on the iterator
|
||||
* may terminate the iteration early.
|
||||
* <br>
|
||||
* We suggest you try the method useLines() instead which closes the stream when the processing is complete.
|
||||
*/
|
||||
public fun BufferedReader.lines(): Stream<String> = LinesStream(this)
|
||||
|
||||
deprecated("Use lines() function which returns Stream<String>")
|
||||
public fun BufferedReader.lineIterator(): Iterator<String> = lines().iterator()
|
||||
|
||||
private class LinesStream(private val reader: BufferedReader) : Stream<String> {
|
||||
override fun iterator(): Iterator<String> {
|
||||
return object : Iterator<String> {
|
||||
private var nextValue: String? = null
|
||||
private var done = false
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (nextValue == null && !done) {
|
||||
nextValue = reader.readLine()
|
||||
if (nextValue == null) done = true
|
||||
}
|
||||
return nextValue != null
|
||||
}
|
||||
|
||||
public override fun next(): String {
|
||||
if (!hasNext()) {
|
||||
throw NoSuchElementException()
|
||||
}
|
||||
val answer = nextValue
|
||||
nextValue = null
|
||||
return answer!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads this reader completely as a String
|
||||
*
|
||||
* **Note** it is the callers responsibility to close this resource
|
||||
*/
|
||||
public fun Reader.readText(): String {
|
||||
val buffer = StringWriter()
|
||||
copyTo(buffer)
|
||||
return buffer.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies this reader to the given output writer, returning the number of bytes copied.
|
||||
*
|
||||
* **Note** it is the callers responsibility to close both of these resources
|
||||
*/
|
||||
public fun Reader.copyTo(out: Writer, bufferSize: Int = defaultBufferSize): Long {
|
||||
var charsCopied: Long = 0
|
||||
val buffer = CharArray(bufferSize)
|
||||
var chars = read(buffer)
|
||||
while (chars >= 0) {
|
||||
out.write(buffer, 0, chars)
|
||||
charsCopied += chars
|
||||
chars = read(buffer)
|
||||
}
|
||||
return charsCopied
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entire content of the URL as a String using specified charset.
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun URL.readText(charset: String): String = readBytes().toString(charset)
|
||||
|
||||
/**
|
||||
* Reads the entire content of the URL as a String using UTF-8 or specified charset..
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun URL.readText(charset: Charset = Charsets.UTF_8): String = readBytes().toString(charset)
|
||||
|
||||
/**
|
||||
* Reads the entire content of the URL as bytes
|
||||
*
|
||||
* This method is not recommended on huge files.
|
||||
*/
|
||||
public fun URL.readBytes(): ByteArray = this.openStream()!!.use<InputStream, ByteArray>{ it.readBytes() }
|
||||
|
||||
/** Uses the given resource then closes it down correctly whether an exception is thrown or not */
|
||||
public inline fun <T : Closeable, R> T.use(block: (T) -> R): R {
|
||||
var closed = false
|
||||
try {
|
||||
return block(this)
|
||||
} catch (e: Exception) {
|
||||
closed = true
|
||||
try {
|
||||
this.close()
|
||||
} catch (closeException: Exception) {
|
||||
// eat the closeException as we are already throwing the original cause
|
||||
// and we don't want to mask the real exception
|
||||
|
||||
// TODO on Java 7 we should call
|
||||
// e.addSuppressed(closeException)
|
||||
// to work like try-with-resources
|
||||
// http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html#suppressed-exceptions
|
||||
}
|
||||
throw e
|
||||
} finally {
|
||||
if (!closed) {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user