Add java.nio.Path extensions to stdlib-jdk7: part 2
- Add notExists - Rename isFile to isRegularFile - Remove forEachBlock - Rename listFiles - Add relativeTo extensions - Remove extra overloads - Update doc comments - Address review comments #KT-19192
This commit is contained in:
@@ -17,43 +17,13 @@ import java.nio.file.OpenOption
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.StandardOpenOption
|
import java.nio.file.StandardOpenOption
|
||||||
|
|
||||||
/**
|
|
||||||
* The default block size for forEachBlock().
|
|
||||||
*/
|
|
||||||
private const val DEFAULT_BLOCK_SIZE: Int = 4096
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The minimum block size for forEachBlock().
|
|
||||||
*/
|
|
||||||
private const val MINIMUM_BLOCK_SIZE: Int = 512
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new [InputStreamReader] for reading the content of this file.
|
* Returns a new [InputStreamReader] for reading the content of this file.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
public inline fun Path.reader(charset: Charset = Charsets.UTF_8): InputStreamReader {
|
public inline fun Path.reader(charset: Charset = Charsets.UTF_8, vararg options: OpenOption): InputStreamReader {
|
||||||
return inputStream().reader(charset)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [InputStreamReader] for reading the content of this file.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.reader(vararg options: OpenOption): InputStreamReader {
|
|
||||||
return inputStream(*options).reader()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [InputStreamReader] for reading the content of this file.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.reader(charset: Charset, vararg options: OpenOption): InputStreamReader {
|
|
||||||
return inputStream(*options).reader(charset)
|
return inputStream(*options).reader(charset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,63 +32,16 @@ public inline fun Path.reader(charset: Charset, vararg options: OpenOption): Inp
|
|||||||
*
|
*
|
||||||
* @param charset character set to use.
|
* @param charset character set to use.
|
||||||
* @param bufferSize necessary size of the buffer.
|
* @param bufferSize necessary size of the buffer.
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.bufferedReader(charset: Charset = Charsets.UTF_8, bufferSize: Int = DEFAULT_BUFFER_SIZE): BufferedReader {
|
|
||||||
return reader(charset).buffered(bufferSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [BufferedReader] for reading the content of this file.
|
|
||||||
*
|
|
||||||
* @param options options to determine how the file is opened
|
* @param options options to determine how the file is opened
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
public inline fun Path.bufferedReader(vararg options: OpenOption): BufferedReader {
|
public inline fun Path.bufferedReader(
|
||||||
return reader(*options).buffered()
|
charset: Charset = Charsets.UTF_8,
|
||||||
}
|
bufferSize: Int = DEFAULT_BUFFER_SIZE,
|
||||||
|
vararg options: OpenOption
|
||||||
/**
|
): BufferedReader {
|
||||||
* Returns a new [BufferedReader] for reading the content of this file.
|
|
||||||
*
|
|
||||||
* @param bufferSize necessary size of the buffer.
|
|
||||||
* @param options options to determine how the file is opened
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.bufferedReader(bufferSize: Int, vararg options: OpenOption): BufferedReader {
|
|
||||||
return reader(*options).buffered(bufferSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [BufferedReader] for reading the content of this file.
|
|
||||||
*
|
|
||||||
* @param charset character set to use.
|
|
||||||
* @param options options to determine how the file is opened
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.bufferedReader(charset: Charset, vararg options: OpenOption): BufferedReader {
|
|
||||||
return reader(charset, *options).buffered()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [BufferedReader] for reading the content of this file.
|
|
||||||
*
|
|
||||||
* @param charset character set to use.
|
|
||||||
* @param bufferSize necessary size of the buffer.
|
|
||||||
* @param options options to determine how the file is opened
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.bufferedReader(charset: Charset, bufferSize: Int, vararg options: OpenOption): BufferedReader {
|
|
||||||
return reader(charset, *options).buffered(bufferSize)
|
return reader(charset, *options).buffered(bufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,27 +51,7 @@ public inline fun Path.bufferedReader(charset: Charset, bufferSize: Int, vararg
|
|||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
public inline fun Path.writer(charset: Charset = Charsets.UTF_8): OutputStreamWriter {
|
public inline fun Path.writer(charset: Charset = Charsets.UTF_8, vararg options: OpenOption): OutputStreamWriter {
|
||||||
return outputStream().writer(charset)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [OutputStreamWriter] for writing the content of this file.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.writer(vararg options: OpenOption): OutputStreamWriter {
|
|
||||||
return outputStream(*options).writer()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [OutputStreamWriter] for writing the content of this file.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.writer(charset: Charset, vararg options: OpenOption): OutputStreamWriter {
|
|
||||||
return outputStream(*options).writer(charset)
|
return outputStream(*options).writer(charset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,63 +60,16 @@ public inline fun Path.writer(charset: Charset, vararg options: OpenOption): Out
|
|||||||
*
|
*
|
||||||
* @param charset character set to use.
|
* @param charset character set to use.
|
||||||
* @param bufferSize necessary size of the buffer.
|
* @param bufferSize necessary size of the buffer.
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.bufferedWriter(charset: Charset = Charsets.UTF_8, bufferSize: Int = DEFAULT_BUFFER_SIZE): BufferedWriter {
|
|
||||||
return writer(charset).buffered(bufferSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [BufferedWriter] for writing the content of this file.
|
|
||||||
*
|
|
||||||
* @param options options to determine how the file is opened.
|
* @param options options to determine how the file is opened.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
public inline fun Path.bufferedWriter(vararg options: OpenOption): BufferedWriter {
|
public inline fun Path.bufferedWriter(
|
||||||
return writer(*options).buffered()
|
charset: Charset = Charsets.UTF_8,
|
||||||
}
|
bufferSize: Int = DEFAULT_BUFFER_SIZE,
|
||||||
|
vararg options: OpenOption
|
||||||
/**
|
): BufferedWriter {
|
||||||
* Returns a new [BufferedWriter] for writing the content of this file.
|
|
||||||
*
|
|
||||||
* @param charset character set to use.
|
|
||||||
* @param options options to determine how the file is opened.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.bufferedWriter(charset: Charset, vararg options: OpenOption): BufferedWriter {
|
|
||||||
return writer(charset, *options).buffered()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [BufferedWriter] for writing the content of this file.
|
|
||||||
*
|
|
||||||
* @param bufferSize necessary size of the buffer.
|
|
||||||
* @param options options to determine how the file is opened.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.bufferedWriter(bufferSize: Int, vararg options: OpenOption): BufferedWriter {
|
|
||||||
return writer(*options).buffered(bufferSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [BufferedWriter] for writing the content of this file.
|
|
||||||
*
|
|
||||||
* @param charset character set to use.
|
|
||||||
* @param bufferSize necessary size of the buffer.
|
|
||||||
* @param options options to determine how the file is opened.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.bufferedWriter(charset: Charset, bufferSize: Int, vararg options: OpenOption): BufferedWriter {
|
|
||||||
return writer(charset, *options).buffered(bufferSize)
|
return writer(charset, *options).buffered(bufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,28 +79,8 @@ public inline fun Path.bufferedWriter(charset: Charset, bufferSize: Int, vararg
|
|||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
public inline fun Path.printWriter(charset: Charset = Charsets.UTF_8): PrintWriter {
|
public inline fun Path.printWriter(charset: Charset = Charsets.UTF_8, vararg options: OpenOption): PrintWriter {
|
||||||
return PrintWriter(bufferedWriter(charset))
|
return PrintWriter(bufferedWriter(charset, options = options))
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [PrintWriter] for writing the content of this file.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.printWriter(vararg options: OpenOption): PrintWriter {
|
|
||||||
return PrintWriter(bufferedWriter(*options))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new [PrintWriter] for writing the content of this file.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
@kotlin.internal.InlineOnly
|
|
||||||
public inline fun Path.printWriter(charset: Charset, vararg options: OpenOption): PrintWriter {
|
|
||||||
return PrintWriter(bufferedWriter(charset, *options))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -301,20 +137,6 @@ public inline fun Path.appendBytes(array: ByteArray): Unit {
|
|||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
public fun Path.readText(charset: Charset = Charsets.UTF_8): String = readBytes().toString(charset)
|
public fun Path.readText(charset: Charset = Charsets.UTF_8): String = readBytes().toString(charset)
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the content of this file as [text] encoded using UTF-8 or specified [charset].
|
|
||||||
*
|
|
||||||
* By default, the file will be overwritten if it already exists, but you can control this behavior
|
|
||||||
* with [options].
|
|
||||||
*
|
|
||||||
* @param text text to write into file.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
public fun Path.writeText(text: String, vararg options: OpenOption): Unit {
|
|
||||||
writeBytes(text.toByteArray(), *options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the content of this file as [text] encoded using UTF-8 or specified [charset].
|
* Sets the content of this file as [text] encoded using UTF-8 or specified [charset].
|
||||||
*
|
*
|
||||||
@@ -326,25 +148,10 @@ public fun Path.writeText(text: String, vararg options: OpenOption): Unit {
|
|||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
public fun Path.writeText(text: String, charset: Charset, vararg options: OpenOption): Unit {
|
public fun Path.writeText(text: String, charset: Charset = Charsets.UTF_8, vararg options: OpenOption): Unit {
|
||||||
writeBytes(text.toByteArray(charset), *options)
|
writeBytes(text.toByteArray(charset), *options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the content of this file as [text] encoded using UTF-8 or specified [charset].
|
|
||||||
* If this file exists, it becomes overwritten.
|
|
||||||
*
|
|
||||||
* @param text text to write into file.
|
|
||||||
* @param charset character set to use.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
public fun Path.writeText(text: String, charset: Charset = Charsets.UTF_8): Unit {
|
|
||||||
writeBytes(text.toByteArray(charset))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends [text] to the content of this file using UTF-8 or the specified [charset].
|
* Appends [text] to the content of this file using UTF-8 or the specified [charset].
|
||||||
*
|
*
|
||||||
@@ -357,45 +164,6 @@ public fun Path.appendText(text: String, charset: Charset = Charsets.UTF_8): Uni
|
|||||||
writeText(text, charset, StandardOpenOption.APPEND)
|
writeText(text, charset, StandardOpenOption.APPEND)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads file by byte blocks and calls [action] for each block read.
|
|
||||||
* Block has default size which is implementation-dependent.
|
|
||||||
* This function passes the byte array and amount of bytes in the array to the [action] function.
|
|
||||||
*
|
|
||||||
* You can use this function for huge files.
|
|
||||||
*
|
|
||||||
* @param action function to process file blocks.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
public fun Path.forEachBlock(action: (buffer: ByteArray, bytesRead: Int) -> Unit): Unit = forEachBlock(DEFAULT_BLOCK_SIZE, action)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads file by byte blocks and calls [action] for each block read.
|
|
||||||
* This functions passes the byte array and amount of bytes in the array to the [action] function.
|
|
||||||
*
|
|
||||||
* You can use this function for huge files.
|
|
||||||
*
|
|
||||||
* @param action function to process file blocks.
|
|
||||||
* @param blockSize size of a block, replaced by 512 if it's less, 4096 by default.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
public fun Path.forEachBlock(blockSize: Int, action: (buffer: ByteArray, bytesRead: Int) -> Unit): Unit {
|
|
||||||
val arr = ByteArray(blockSize.coerceAtLeast(MINIMUM_BLOCK_SIZE))
|
|
||||||
|
|
||||||
inputStream().use { input ->
|
|
||||||
do {
|
|
||||||
val size = input.read(arr)
|
|
||||||
if (size <= 0) {
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
action(arr, size)
|
|
||||||
}
|
|
||||||
} while (true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads this file line by line using the specified [charset] and calls [action] for each line.
|
* Reads this file line by line using the specified [charset] and calls [action] for each line.
|
||||||
* Default charset is UTF-8.
|
* Default charset is UTF-8.
|
||||||
@@ -408,29 +176,13 @@ public fun Path.forEachBlock(blockSize: Int, action: (buffer: ByteArray, bytesRe
|
|||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
public fun Path.forEachLine(vararg options: OpenOption, charset: Charset = Charsets.UTF_8, action: (line: String) -> Unit): Unit {
|
public fun Path.forEachLine(charset: Charset = Charsets.UTF_8, vararg options: OpenOption, action: (line: String) -> Unit): Unit {
|
||||||
// Note: close is called at forEachLine
|
// Note: close is called at forEachLine
|
||||||
bufferedReader(charset, *options).forEachLine(action)
|
bufferedReader(charset, options = options).forEachLine(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads this file line by line using the specified [charset] and calls [action] for each line.
|
* Constructs a new InputStream of this file and returns it as a result.
|
||||||
* Default charset is UTF-8.
|
|
||||||
*
|
|
||||||
* You may use this function on huge files.
|
|
||||||
*
|
|
||||||
* @param charset character set to use.
|
|
||||||
* @param action function to process file lines.
|
|
||||||
*/
|
|
||||||
@SinceKotlin("1.4")
|
|
||||||
@ExperimentalStdlibApi
|
|
||||||
public fun Path.forEachLine(charset: Charset = Charsets.UTF_8, action: (line: String) -> Unit): Unit {
|
|
||||||
// Note: close is called at forEachLine
|
|
||||||
bufferedReader(charset = charset).forEachLine(action)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new InputStream of this path and returns it as a result.
|
|
||||||
*
|
*
|
||||||
* The [options] parameter determines how the file is opened. If no options are present then it is
|
* The [options] parameter determines how the file is opened. If no options are present then it is
|
||||||
* equivalent to opening the file with the [READ][StandardOpenOption.READ] option.
|
* equivalent to opening the file with the [READ][StandardOpenOption.READ] option.
|
||||||
@@ -448,7 +200,7 @@ public inline fun Path.inputStream(vararg options: OpenOption): InputStream {
|
|||||||
* The [options] parameter determines how the file is opened. If no options are present then it is
|
* The [options] parameter determines how the file is opened. If no options are present then it is
|
||||||
* equivalent to opening the file with the [CREATE][StandardOpenOption.CREATE],
|
* equivalent to opening the file with the [CREATE][StandardOpenOption.CREATE],
|
||||||
* [TRUNCATE_EXISTING][StandardOpenOption.TRUNCATE_EXISTING], and [WRITE][StandardOpenOption.WRITE]
|
* [TRUNCATE_EXISTING][StandardOpenOption.TRUNCATE_EXISTING], and [WRITE][StandardOpenOption.WRITE]
|
||||||
* option.
|
* options.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
|
|||||||
@@ -10,23 +10,21 @@
|
|||||||
|
|
||||||
package kotlin.io
|
package kotlin.io
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.channels.FileChannel
|
|
||||||
import java.nio.file.*
|
import java.nio.file.*
|
||||||
import java.nio.file.FileAlreadyExistsException
|
import java.nio.file.FileAlreadyExistsException
|
||||||
import java.nio.file.NoSuchFileException
|
import java.nio.file.NoSuchFileException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extension of this file (not including the dot), or an empty string if it doesn't have one.
|
* Returns the extension of this path (not including the dot), or an empty string if it doesn't have one.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
public val Path.extension: String
|
public val Path.extension: String
|
||||||
get() = fileName.toString().substringAfterLast('.', "")
|
get() = fileName?.toString()?.substringAfterLast('.', "") ?: ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns [path][File.path] of this File using the invariant separator '/' to
|
* Returns this path as a [String] using the invariant separator '/' to
|
||||||
* separate the names in the name sequence.
|
* separate the names in the name sequence.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@@ -38,13 +36,55 @@ public val Path.invariantSeparatorsPath: String
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns file's name without an extension.
|
* Returns this path's [fileName][Path.getFileName] without an extension, or an empty string if
|
||||||
|
* this path has zero elements.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
public val Path.nameWithoutExtension: String
|
public val Path.nameWithoutExtension: String
|
||||||
get() = fileName.toString().substringBeforeLast(".")
|
get() = fileName?.toString()?.substringBeforeLast(".") ?: ""
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the relative path for this path from a [base] path.
|
||||||
|
* Note that the [base] path is treated as a directory.
|
||||||
|
* If this path matches the [base] path, then a [Path] with an empty path will be returned.
|
||||||
|
*
|
||||||
|
* @return Path with relative path from [base] to this.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if this and base paths have different roots.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.4")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public fun Path.relativeTo(base: Path): Path = base.relativize(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the relative path for this path from a [base] path.
|
||||||
|
* Note that the [base] path is treated as a directory.
|
||||||
|
* If this path matches the [base] path, then a [Path] with an empty path will be returned.
|
||||||
|
*
|
||||||
|
* @return Path with relative path from [base] to this, or `this` if this and base paths have different roots.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.4")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public fun Path.relativeToOrSelf(base: Path): Path =
|
||||||
|
relativeToOrNull(base) ?: this
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the relative path for this path from a [base] path.
|
||||||
|
* Note that the [base] path is treated as a directory.
|
||||||
|
* If this path matches the [base] path, then a [Path] with an empty path will be returned.
|
||||||
|
*
|
||||||
|
* @return Path with relative path from [base] to this, or `null` if this and base paths have different roots.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.4")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public fun Path.relativeToOrNull(base: Path): Path? {
|
||||||
|
return try {
|
||||||
|
base.relativize(this)
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies this path to the given [target] path.
|
* Copies this path to the given [target] path.
|
||||||
@@ -54,15 +94,15 @@ public val Path.nameWithoutExtension: String
|
|||||||
*
|
*
|
||||||
* When [overwrite] is `true` and [target] is a directory, it is replaced only if it is empty.
|
* When [overwrite] is `true` and [target] is a directory, it is replaced only if it is empty.
|
||||||
*
|
*
|
||||||
* If this file is a directory, it is copied without its content, i.e. an empty [target] directory is created.
|
* If this path is a directory, it is copied without its content, i.e. an empty [target] directory is created.
|
||||||
* If you want to copy directory including its contents, use [copyRecursively].
|
* If you want to copy directory including its contents, use [copyRecursively].
|
||||||
*
|
*
|
||||||
* The operation doesn't preserve copied file attributes such as creation/modification date, permissions, etc.
|
* The operation doesn't preserve copied file attributes such as creation/modification date, permissions, etc.
|
||||||
*
|
*
|
||||||
* @param overwrite `true` if destination overwrite is allowed.
|
* @param overwrite `true` if destination overwrite is allowed.
|
||||||
* @return the [target] file.
|
* @return the [target] path.
|
||||||
* @throws NoSuchFileException if the source file doesn't exist.
|
* @throws NoSuchFileException if the source path doesn't exist.
|
||||||
* @throws FileAlreadyExistsException if the destination file already exists and [overwrite] argument is set to `false`.
|
* @throws FileAlreadyExistsException if the destination path already exists and [overwrite] argument is set to `false`.
|
||||||
* @throws IOException if any errors occur while copying.
|
* @throws IOException if any errors occur while copying.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@@ -82,32 +122,32 @@ public fun Path.copyTo(target: Path, overwrite: Boolean = false): Path {
|
|||||||
* When [REPLACE_EXISTING][StandardCopyOption.REPLACE_EXISTING] is used and [target] is a directory,
|
* When [REPLACE_EXISTING][StandardCopyOption.REPLACE_EXISTING] is used and [target] is a directory,
|
||||||
* it is replaced only if it is empty.
|
* it is replaced only if it is empty.
|
||||||
*
|
*
|
||||||
* If this file is a directory, it is copied without its content, i.e. an empty [target] directory is created.
|
* If this path is a directory, it is copied without its content, i.e. an empty [target] directory is created.
|
||||||
* If you want to copy directory including its contents, use [copyRecursively].
|
* If you want to copy directory including its contents, use [copyRecursively].
|
||||||
*
|
*
|
||||||
* The operation doesn't preserve copied file attributes such as creation/modification date,
|
* The operation doesn't preserve copied file attributes such as creation/modification date,
|
||||||
* permissions, etc. unless [COPY_ATTRIBUTES][StandardCopyOption.COPY_ATTRIBUTES] is used.
|
* permissions, etc. unless [COPY_ATTRIBUTES][StandardCopyOption.COPY_ATTRIBUTES] is used.
|
||||||
*
|
*
|
||||||
* @param options options to control how the path is copied.
|
* @param options options to control how the path is copied.
|
||||||
* @return the [target] file.
|
* @return the [target] path.
|
||||||
* @throws NoSuchFileException if the source file doesn't exist.
|
* @throws NoSuchFileException if the source path doesn't exist.
|
||||||
* @throws FileAlreadyExistsException if the destination file already exists and [REPLACE_EXISTING][StandardCopyOption.REPLACE_EXISTING] is not used.
|
* @throws FileAlreadyExistsException if the destination path already exists and [REPLACE_EXISTING][StandardCopyOption.REPLACE_EXISTING] is not used.
|
||||||
* @throws IOException if any errors occur while copying.
|
* @throws IOException if any errors occur while copying.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
public fun Path.copyTo(target: Path, vararg options: CopyOption): Path {
|
public fun Path.copyTo(target: Path, vararg options: CopyOption): Path {
|
||||||
if (!this.exists()) {
|
if (this.notExists()) {
|
||||||
throw NoSuchFileException(toString(), null, "The source file doesn't exist.")
|
throw NoSuchFileException(toString(), null, "The source path doesn't exist.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.exists() && StandardCopyOption.REPLACE_EXISTING !in options) {
|
if (target.exists() && StandardCopyOption.REPLACE_EXISTING !in options) {
|
||||||
throw FileAlreadyExistsException(toString(), null, "The destination file already exists.")
|
throw FileAlreadyExistsException(toString(), null, "The destination path already exists.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isDirectory()) {
|
if (this.isDirectory()) {
|
||||||
if (target.isDirectory() && Files.newDirectoryStream(target).use { it.firstOrNull() } != null) {
|
if (target.isDirectory() && Files.newDirectoryStream(target).use { it.firstOrNull() } != null) {
|
||||||
throw FileAlreadyExistsException(toString(), null, "The destination file already exists.")
|
throw FileAlreadyExistsException(toString(), null, "The destination path already exists.")
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(target)
|
Files.createDirectories(target)
|
||||||
@@ -125,7 +165,7 @@ public fun Path.copyTo(target: Path, vararg options: CopyOption): Path {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this file exists.
|
* Check if this path exists.
|
||||||
*
|
*
|
||||||
* @param options Options to control how symbolic links are handled.
|
* @param options Options to control how symbolic links are handled.
|
||||||
*/
|
*/
|
||||||
@@ -134,6 +174,16 @@ public fun Path.copyTo(target: Path, vararg options: CopyOption): Path {
|
|||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
public inline fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options)
|
public inline fun Path.exists(vararg options: LinkOption): Boolean = Files.exists(this, *options)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this path does not exist.
|
||||||
|
*
|
||||||
|
* @param options Options to control how symbolic links are handled.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.4")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
@kotlin.internal.InlineOnly
|
||||||
|
public inline fun Path.notExists(vararg options: LinkOption): Boolean = Files.notExists(this, *options)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this path is a file.
|
* Check if this path is a file.
|
||||||
*
|
*
|
||||||
@@ -142,7 +192,7 @@ public inline fun Path.exists(vararg options: LinkOption): Boolean = Files.exist
|
|||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@kotlin.internal.InlineOnly
|
@kotlin.internal.InlineOnly
|
||||||
public inline fun Path.isFile(vararg options: LinkOption): Boolean = Files.isRegularFile(this, *options)
|
public inline fun Path.isRegularFile(vararg options: LinkOption): Boolean = Files.isRegularFile(this, *options)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this path is a directory.
|
* Check if this path is a directory.
|
||||||
@@ -208,13 +258,38 @@ public inline fun Path.isWritable(): Boolean = Files.isWritable(this)
|
|||||||
public inline fun Path.isSameFile(other: Path): Boolean = Files.isSameFile(this, other)
|
public inline fun Path.isSameFile(other: Path): Boolean = Files.isSameFile(this, other)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of the files and directories in this directory.
|
* Return a list of the entries in this directory.
|
||||||
*
|
*
|
||||||
* @throws NotDirectoryException If this path does not refer to a directory
|
* @throws NotDirectoryException If this path does not refer to a directory
|
||||||
* @throws IOException If an I/O error occurs
|
* @throws IOException If an I/O error occurs
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.4")
|
@SinceKotlin("1.4")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
public fun Path.listFiles(): List<Path> {
|
public fun Path.listDirectoryEntries(): List<Path> {
|
||||||
return Files.newDirectoryStream(this).use { it.toList() }
|
return Files.newDirectoryStream(this).use { it.toList() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the [block] callback with a sequence of all entries in this directory.
|
||||||
|
*
|
||||||
|
* @throws NotDirectoryException If this path does not refer to a directory
|
||||||
|
* @throws IOException If an I/O error occurs
|
||||||
|
* @return the value returned by [block]
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.4")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public fun <T> Path.useDirectoryEntries(block: (Sequence<Path>) -> T): T {
|
||||||
|
return Files.newDirectoryStream(this).use { block(it.asSequence()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform the given [action] on each entry in this directory.
|
||||||
|
*
|
||||||
|
* @throws NotDirectoryException If this path does not refer to a directory
|
||||||
|
* @throws IOException If an I/O error occurs
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.4")
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
public fun Path.forEachDirectoryEntry(action: (Path) -> Unit) {
|
||||||
|
return Files.newDirectoryStream(this).use { it.forEach(action) }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kotlin.jdk7.test
|
package kotlin.jdk7.test
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
import java.nio.file.*
|
import java.nio.file.*
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
class PathExtensionsTest {
|
class PathExtensionsTest {
|
||||||
|
private val isCaseInsensitiveFileSystem = Paths.get("C:/") == Paths.get("c:/")
|
||||||
|
private val isBackslashSeparator = FileSystems.getDefault().separator == "\\"
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun extension() {
|
fun extension() {
|
||||||
assertEquals("bbb", Paths.get("aaa.bbb").extension)
|
assertEquals("bbb", Paths.get("aaa.bbb").extension)
|
||||||
assertEquals("", Paths.get("aaa").extension)
|
assertEquals("", Paths.get("aaa").extension)
|
||||||
assertEquals("", Paths.get("aaa.").extension)
|
assertEquals("", Paths.get("aaa.").extension)
|
||||||
// maybe we should think that such files have name .bbb and no extension
|
|
||||||
assertEquals("bbb", Paths.get(".bbb").extension)
|
assertEquals("bbb", Paths.get(".bbb").extension)
|
||||||
assertEquals("", Paths.get("/my.dir/log").extension)
|
assertEquals("", Paths.get("/my.dir/log").extension)
|
||||||
|
assertEquals("", Paths.get("/").extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -27,6 +30,8 @@ class PathExtensionsTest {
|
|||||||
assertEquals("aaa", Paths.get("aaa.").nameWithoutExtension)
|
assertEquals("aaa", Paths.get("aaa.").nameWithoutExtension)
|
||||||
assertEquals("", Paths.get(".bbb").nameWithoutExtension)
|
assertEquals("", Paths.get(".bbb").nameWithoutExtension)
|
||||||
assertEquals("log", Paths.get("/my.dir/log").nameWithoutExtension)
|
assertEquals("log", Paths.get("/my.dir/log").nameWithoutExtension)
|
||||||
|
assertEquals("", Paths.get("").nameWithoutExtension)
|
||||||
|
assertEquals("", Paths.get("/").nameWithoutExtension)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -74,7 +79,7 @@ class PathExtensionsTest {
|
|||||||
}
|
}
|
||||||
srcFile.copyTo(dstFile, overwrite = true)
|
srcFile.copyTo(dstFile, overwrite = true)
|
||||||
assertTrue(dstFile.isDirectory())
|
assertTrue(dstFile.isDirectory())
|
||||||
assertTrue(dstFile.listFiles().isEmpty(), "only directory is copied, but not its content")
|
assertTrue(dstFile.listDirectoryEntries().isEmpty(), "only directory is copied, but not its content")
|
||||||
|
|
||||||
assertFailsWith(FileAlreadyExistsException::class, "copy dir do not overwrite dir") {
|
assertFailsWith(FileAlreadyExistsException::class, "copy dir do not overwrite dir") {
|
||||||
srcFile.copyTo(dstFile)
|
srcFile.copyTo(dstFile)
|
||||||
@@ -82,7 +87,7 @@ class PathExtensionsTest {
|
|||||||
|
|
||||||
srcFile.copyTo(dstFile, overwrite = true)
|
srcFile.copyTo(dstFile, overwrite = true)
|
||||||
assertTrue(dstFile.isDirectory())
|
assertTrue(dstFile.isDirectory())
|
||||||
assertTrue(dstFile.listFiles().isEmpty(), "only directory is copied, but not its content")
|
assertTrue(dstFile.listDirectoryEntries().isEmpty(), "only directory is copied, but not its content")
|
||||||
|
|
||||||
dstFile.resolve("somefile2").writeText("some content2")
|
dstFile.resolve("somefile2").writeText("some content2")
|
||||||
assertFailsWith(FileAlreadyExistsException::class, "copy dir do not overwrite non-empty dir") {
|
assertFailsWith(FileAlreadyExistsException::class, "copy dir do not overwrite non-empty dir") {
|
||||||
@@ -116,79 +121,18 @@ class PathExtensionsTest {
|
|||||||
|
|
||||||
private fun compareFiles(src: Path, dst: Path, message: String? = null) {
|
private fun compareFiles(src: Path, dst: Path, message: String? = null) {
|
||||||
assertTrue(dst.exists())
|
assertTrue(dst.exists())
|
||||||
assertEquals(src.isFile(), dst.isFile(), message)
|
assertEquals(src.isRegularFile(), dst.isRegularFile(), message)
|
||||||
if (dst.isFile()) {
|
if (dst.isRegularFile()) {
|
||||||
assertTrue(src.readBytes().contentEquals(dst.readBytes()), message)
|
assertTrue(src.readBytes().contentEquals(dst.readBytes()), message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBufferedReader() {
|
fun testAttributeGettersOnFile() {
|
||||||
val file = Files.createTempFile(null, null)
|
|
||||||
val lines = listOf("line1", "line2")
|
|
||||||
Files.write(file, lines)
|
|
||||||
|
|
||||||
assertEquals(file.bufferedReader().use { it.readLines() }, lines)
|
|
||||||
assertEquals(file.bufferedReader(StandardOpenOption.READ).use { it.readLines() }, lines)
|
|
||||||
assertEquals(file.bufferedReader(1024, StandardOpenOption.READ).use { it.readLines() }, lines)
|
|
||||||
assertEquals(file.bufferedReader(Charsets.UTF_8, StandardOpenOption.READ).use { it.readLines() }, lines)
|
|
||||||
assertEquals(file.bufferedReader(Charsets.UTF_8, 1024, StandardOpenOption.READ).use { it.readLines() }, lines)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testBufferedWriter() {
|
|
||||||
val file = Files.createTempFile(null, null)
|
|
||||||
|
|
||||||
file.bufferedWriter().use { it.write("line1\n") }
|
|
||||||
file.bufferedWriter(StandardOpenOption.APPEND).use { it.write("line2\n") }
|
|
||||||
file.bufferedWriter(Charsets.UTF_8, StandardOpenOption.APPEND).use { it.write("line3\n") }
|
|
||||||
file.bufferedWriter(1024, StandardOpenOption.APPEND).use { it.write("line4\n") }
|
|
||||||
file.bufferedWriter(Charsets.UTF_8, 1024, StandardOpenOption.APPEND).use { it.write("line5\n") }
|
|
||||||
|
|
||||||
assertEquals(Files.readAllLines(file), listOf("line1", "line2", "line3", "line4", "line5"))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testPrintWriter() {
|
|
||||||
val file = Files.createTempFile(null, null)
|
|
||||||
|
|
||||||
val writer = file.printWriter()
|
|
||||||
val str1 = "Hello, world!"
|
|
||||||
val str2 = "Everything is wonderful!"
|
|
||||||
writer.println(str1)
|
|
||||||
writer.println(str2)
|
|
||||||
writer.close()
|
|
||||||
|
|
||||||
val writer2 = file.printWriter(StandardOpenOption.APPEND)
|
|
||||||
val str3 = "Hello again!"
|
|
||||||
writer2.println(str3)
|
|
||||||
writer2.close()
|
|
||||||
|
|
||||||
val writer3 = file.printWriter(Charsets.UTF_8, StandardOpenOption.APPEND)
|
|
||||||
val str4 = "Hello one last time!"
|
|
||||||
writer3.println(str4)
|
|
||||||
writer3.close()
|
|
||||||
|
|
||||||
val reader = file.bufferedReader()
|
|
||||||
assertEquals(str1, reader.readLine())
|
|
||||||
assertEquals(str2, reader.readLine())
|
|
||||||
assertEquals(str3, reader.readLine())
|
|
||||||
assertEquals(str4, reader.readLine())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testWriteBytes() {
|
|
||||||
val file = Files.createTempFile(null, null)
|
|
||||||
file.writeBytes("Hello".encodeToByteArray())
|
|
||||||
file.appendBytes(" world!".encodeToByteArray())
|
|
||||||
assertEquals(file.readText(), "Hello world!")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testAttributeGetters() {
|
|
||||||
val file = Files.createTempFile(null, null)
|
val file = Files.createTempFile(null, null)
|
||||||
assertTrue(file.exists())
|
assertTrue(file.exists())
|
||||||
assertTrue(file.isFile())
|
assertFalse(file.notExists())
|
||||||
|
assertTrue(file.isRegularFile())
|
||||||
assertFalse(file.isDirectory())
|
assertFalse(file.isDirectory())
|
||||||
assertFalse(file.isSymbolicLink())
|
assertFalse(file.isSymbolicLink())
|
||||||
assertTrue(file.isReadable())
|
assertTrue(file.isReadable())
|
||||||
@@ -202,14 +146,191 @@ class PathExtensionsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testListFiles() {
|
fun testAttributeGettersOnDirectory() {
|
||||||
|
val file = Files.createTempDirectory(null)
|
||||||
|
assertTrue(file.exists())
|
||||||
|
assertFalse(file.notExists())
|
||||||
|
assertFalse(file.isRegularFile())
|
||||||
|
assertTrue(file.isDirectory())
|
||||||
|
assertFalse(file.isSymbolicLink())
|
||||||
|
assertTrue(file.isReadable())
|
||||||
|
assertTrue(file.isWritable())
|
||||||
|
assertTrue(file.isSameFile(file))
|
||||||
|
|
||||||
|
file.isExecutable()
|
||||||
|
file.isHidden()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAttributeGettersOnNonExistentPath() {
|
||||||
|
val file = Files.createTempDirectory(null).resolve("foo")
|
||||||
|
assertFalse(file.exists())
|
||||||
|
assertTrue(file.notExists())
|
||||||
|
assertFalse(file.isRegularFile())
|
||||||
|
assertFalse(file.isDirectory())
|
||||||
|
assertFalse(file.isSymbolicLink())
|
||||||
|
assertFalse(file.isReadable())
|
||||||
|
assertFalse(file.isWritable())
|
||||||
|
assertTrue(file.isSameFile(file))
|
||||||
|
|
||||||
|
file.isExecutable()
|
||||||
|
// This function will either throw an exception or return false,
|
||||||
|
// depending on the operating system.
|
||||||
|
try {
|
||||||
|
assertFalse(file.isHidden())
|
||||||
|
} catch (e: IOException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testListDirectoryEntries() {
|
||||||
val dir = Files.createTempDirectory(null)
|
val dir = Files.createTempDirectory(null)
|
||||||
assertEquals(dir.listFiles().size, 0)
|
assertEquals(0, dir.listDirectoryEntries().size)
|
||||||
|
|
||||||
val file = dir.resolve("f1")
|
val file = dir.resolve("f1")
|
||||||
Files.createFile(file)
|
Files.createFile(file)
|
||||||
assertEquals(dir.listFiles().size, 1)
|
assertEquals(listOf(file), dir.listDirectoryEntries())
|
||||||
|
|
||||||
assertFailsWith<NotDirectoryException> { file.listFiles() }
|
assertFailsWith<NotDirectoryException> { file.listDirectoryEntries() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUseDirectoryEntries() {
|
||||||
|
val dir = Files.createTempDirectory(null)
|
||||||
|
assertEquals(0, dir.useDirectoryEntries { it.toList() }.size)
|
||||||
|
|
||||||
|
val file = dir.resolve("f1")
|
||||||
|
Files.createFile(file)
|
||||||
|
assertEquals(listOf(file), dir.useDirectoryEntries { it.toList() })
|
||||||
|
|
||||||
|
assertFailsWith<NotDirectoryException> { file.useDirectoryEntries { it.toList() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testForEachDirectoryEntry() {
|
||||||
|
val dir = Files.createTempDirectory(null)
|
||||||
|
val entries = mutableListOf<Path>()
|
||||||
|
|
||||||
|
dir.forEachDirectoryEntry { entries.add(it) }
|
||||||
|
assertTrue(entries.isEmpty())
|
||||||
|
|
||||||
|
val file = dir.resolve("f1")
|
||||||
|
Files.createFile(file)
|
||||||
|
dir.forEachDirectoryEntry { entries.add(it) }
|
||||||
|
assertEquals(listOf(file), entries)
|
||||||
|
|
||||||
|
assertFailsWith<NotDirectoryException> { file.forEachDirectoryEntry { } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun relativeToRooted() {
|
||||||
|
val file1 = Paths.get("/foo/bar/baz")
|
||||||
|
val file2 = Paths.get("/foo/baa/ghoo")
|
||||||
|
|
||||||
|
assertEquals("../../bar/baz", file1.relativeTo(file2).invariantSeparatorsPath)
|
||||||
|
|
||||||
|
val file3 = Paths.get("/foo/bar")
|
||||||
|
|
||||||
|
assertEquals("baz", file1.relativeTo(file3).toString())
|
||||||
|
assertEquals("..", file3.relativeTo(file1).toString())
|
||||||
|
|
||||||
|
val file4 = Paths.get("/foo/bar/")
|
||||||
|
|
||||||
|
assertEquals("baz", file1.relativeTo(file4).toString())
|
||||||
|
assertEquals("..", file4.relativeTo(file1).toString())
|
||||||
|
assertEquals("", file3.relativeTo(file4).toString())
|
||||||
|
assertEquals("", file4.relativeTo(file3).toString())
|
||||||
|
|
||||||
|
val file5 = Paths.get("/foo/baran")
|
||||||
|
|
||||||
|
assertEquals("../bar", file3.relativeTo(file5).invariantSeparatorsPath)
|
||||||
|
assertEquals("../baran", file5.relativeTo(file3).invariantSeparatorsPath)
|
||||||
|
assertEquals("../bar", file4.relativeTo(file5).invariantSeparatorsPath)
|
||||||
|
assertEquals("../baran", file5.relativeTo(file4).invariantSeparatorsPath)
|
||||||
|
|
||||||
|
if (isBackslashSeparator) {
|
||||||
|
val file6 = Paths.get("C:\\Users\\Me")
|
||||||
|
val file7 = Paths.get("C:\\Users\\Me\\Documents")
|
||||||
|
|
||||||
|
assertEquals("..", file6.relativeTo(file7).toString())
|
||||||
|
assertEquals("Documents", file7.relativeTo(file6).toString())
|
||||||
|
|
||||||
|
val file8 = Paths.get("""\\my.host\home/user/documents/vip""")
|
||||||
|
val file9 = Paths.get("""\\my.host\home/other/images/nice""")
|
||||||
|
|
||||||
|
assertEquals("../../../user/documents/vip", file8.relativeTo(file9).invariantSeparatorsPath)
|
||||||
|
assertEquals("../../../other/images/nice", file9.relativeTo(file8).invariantSeparatorsPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCaseInsensitiveFileSystem) {
|
||||||
|
assertEquals("bar", Paths.get("C:/bar").relativeTo(Paths.get("c:/")).toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun relativeToRelative() {
|
||||||
|
val nested = Paths.get("foo/bar")
|
||||||
|
val base = Paths.get("foo")
|
||||||
|
|
||||||
|
assertEquals("bar", nested.relativeTo(base).toString())
|
||||||
|
assertEquals("..", base.relativeTo(nested).toString())
|
||||||
|
|
||||||
|
val current = Paths.get(".")
|
||||||
|
val parent = Paths.get("..")
|
||||||
|
val outOfRoot = Paths.get("../bar")
|
||||||
|
|
||||||
|
assertEquals(Paths.get("../../bar"), outOfRoot.relativeTo(base))
|
||||||
|
assertEquals("bar", outOfRoot.relativeTo(parent).toString())
|
||||||
|
assertEquals("..", parent.relativeTo(outOfRoot).toString())
|
||||||
|
|
||||||
|
val root = Paths.get("/root")
|
||||||
|
val files = listOf(nested, base, outOfRoot, current, parent)
|
||||||
|
val bases = listOf(nested, base, current)
|
||||||
|
|
||||||
|
for (file in files)
|
||||||
|
assertEquals("", file.relativeTo(file).toString(), "file should have empty path relative to itself: $file")
|
||||||
|
|
||||||
|
for (file in files) {
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
|
for (base in bases) {
|
||||||
|
val rootedFile = root.resolve(file)
|
||||||
|
val rootedBase = root.resolve(base)
|
||||||
|
assertEquals(file.relativeTo(base), rootedFile.relativeTo(rootedBase), "nested: $file, base: $base")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun relativeToFails() {
|
||||||
|
val absolute = Paths.get("/foo/bar/baz")
|
||||||
|
val relative = Paths.get("foo/bar")
|
||||||
|
val networkShare1 = Paths.get("""\\my.host\share1/folder""")
|
||||||
|
val networkShare2 = Paths.get("""\\my.host\share2\folder""")
|
||||||
|
|
||||||
|
fun assertFailsRelativeTo(file: Path, base: Path) {
|
||||||
|
val e = assertFailsWith<IllegalArgumentException>("file: $file, base: $base") { file.relativeTo(base) }
|
||||||
|
assertNotNull(e.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
val allFiles = listOf(absolute, relative) + if (isBackslashSeparator) listOf(networkShare1, networkShare2) else emptyList()
|
||||||
|
for (file in allFiles) {
|
||||||
|
for (base in allFiles) {
|
||||||
|
if (file != base) assertFailsRelativeTo(file, base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBackslashSeparator) {
|
||||||
|
val fileOnC = Paths.get("C:/dir1")
|
||||||
|
val fileOnD = Paths.get("D:/dir2")
|
||||||
|
assertFailsRelativeTo(fileOnC, fileOnD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun relativeTo() {
|
||||||
|
assertEquals("kotlin", Paths.get("src/kotlin").relativeTo(Paths.get("src")).toString())
|
||||||
|
assertEquals("", Paths.get("dir").relativeTo(Paths.get("dir")).toString())
|
||||||
|
assertEquals("..", Paths.get("dir").relativeTo(Paths.get("dir/subdir")).toString())
|
||||||
|
assertEquals(Paths.get("../../test"), Paths.get("test").relativeTo(Paths.get("dir/dir")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -8,9 +8,7 @@ package kotlin.jdk7.test
|
|||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.StandardOpenOption
|
import java.nio.file.StandardOpenOption
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.test.Test
|
import kotlin.test.*
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertTrue
|
|
||||||
|
|
||||||
class PathReadWriteTest {
|
class PathReadWriteTest {
|
||||||
@Test
|
@Test
|
||||||
@@ -18,7 +16,7 @@ class PathReadWriteTest {
|
|||||||
val file = Files.createTempFile(null, null)
|
val file = Files.createTempFile(null, null)
|
||||||
file.writeText("Hello\n")
|
file.writeText("Hello\n")
|
||||||
file.appendText("World\n")
|
file.appendText("World\n")
|
||||||
file.appendText("Again")
|
file.writeText("Again", Charsets.US_ASCII, StandardOpenOption.APPEND)
|
||||||
|
|
||||||
assertEquals("Hello\nWorld\nAgain", file.readText())
|
assertEquals("Hello\nWorld\nAgain", file.readText())
|
||||||
assertEquals(listOf("Hello", "World", "Again"), file.readLines(Charsets.UTF_8))
|
assertEquals(listOf("Hello", "World", "Again"), file.readLines(Charsets.UTF_8))
|
||||||
@@ -35,25 +33,21 @@ class PathReadWriteTest {
|
|||||||
writer.write("World")
|
writer.write("World")
|
||||||
writer.close()
|
writer.close()
|
||||||
|
|
||||||
file.forEachBlock { arr: ByteArray, size: Int ->
|
|
||||||
assertTrue(size in 11..12, size.toString())
|
|
||||||
assertTrue(arr.contains('W'.toByte()))
|
|
||||||
}
|
|
||||||
val list = ArrayList<String>()
|
val list = ArrayList<String>()
|
||||||
file.forEachLine(StandardOpenOption.READ, charset = Charsets.UTF_8) {
|
file.forEachLine(charset = Charsets.UTF_8, options = arrayOf(StandardOpenOption.READ)) {
|
||||||
list.add(it)
|
list.add(it)
|
||||||
}
|
}
|
||||||
assertEquals(arrayListOf("Hello", "World"), list)
|
assertEquals(listOf("Hello", "World"), list)
|
||||||
|
|
||||||
assertEquals(arrayListOf("Hello", "World"), file.readLines())
|
assertEquals(listOf("Hello", "World"), file.readLines())
|
||||||
|
|
||||||
file.useLines {
|
file.useLines {
|
||||||
assertEquals(arrayListOf("Hello", "World"), it.toList())
|
assertEquals(listOf("Hello", "World"), it.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
val text = file.inputStream().reader().readText()
|
val text = file.inputStream().reader().readText()
|
||||||
assertTrue(text.contains("Hello"))
|
assertTrue("Hello" in text)
|
||||||
assertTrue(text.contains("World"))
|
assertTrue("World" in text)
|
||||||
|
|
||||||
file.writeText("")
|
file.writeText("")
|
||||||
var c = 0
|
var c = 0
|
||||||
@@ -76,5 +70,62 @@ class PathReadWriteTest {
|
|||||||
|
|
||||||
file.toFile().deleteOnExit()
|
file.toFile().deleteOnExit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBufferedReader() {
|
||||||
|
val file = Files.createTempFile(null, null)
|
||||||
|
val lines = listOf("line1", "line2")
|
||||||
|
Files.write(file, lines, Charsets.UTF_8)
|
||||||
|
|
||||||
|
assertEquals(file.bufferedReader().use { it.readLines() }, lines)
|
||||||
|
assertEquals(file.bufferedReader(Charsets.UTF_8, 1024, StandardOpenOption.READ).use { it.readLines() }, lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBufferedWriter() {
|
||||||
|
val file = Files.createTempFile(null, null)
|
||||||
|
|
||||||
|
file.bufferedWriter().use { it.write("line1\n") }
|
||||||
|
file.bufferedWriter(Charsets.UTF_8, 1024, StandardOpenOption.APPEND).use { it.write("line2\n") }
|
||||||
|
|
||||||
|
assertEquals(Files.readAllLines(file, Charsets.UTF_8), listOf("line1", "line2"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPrintWriter() {
|
||||||
|
val file = Files.createTempFile(null, null)
|
||||||
|
|
||||||
|
val writer = file.printWriter()
|
||||||
|
val str1 = "Hello, world!"
|
||||||
|
val str2 = "Everything is wonderful!"
|
||||||
|
writer.println(str1)
|
||||||
|
writer.println(str2)
|
||||||
|
writer.close()
|
||||||
|
|
||||||
|
val writer2 = file.printWriter(options = arrayOf(StandardOpenOption.APPEND))
|
||||||
|
val str3 = "Hello again!"
|
||||||
|
writer2.println(str3)
|
||||||
|
writer2.close()
|
||||||
|
|
||||||
|
val writer3 = file.printWriter(Charsets.UTF_8, StandardOpenOption.APPEND)
|
||||||
|
val str4 = "Hello one last time!"
|
||||||
|
writer3.println(str4)
|
||||||
|
writer3.close()
|
||||||
|
|
||||||
|
file.bufferedReader().use { reader ->
|
||||||
|
assertEquals(str1, reader.readLine())
|
||||||
|
assertEquals(str2, reader.readLine())
|
||||||
|
assertEquals(str3, reader.readLine())
|
||||||
|
assertEquals(str4, reader.readLine())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWriteBytes() {
|
||||||
|
val file = Files.createTempFile(null, null)
|
||||||
|
file.writeBytes("Hello".encodeToByteArray())
|
||||||
|
file.appendBytes(" world!".encodeToByteArray())
|
||||||
|
assertEquals(file.readText(), "Hello world!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user