Open-source multiplayer game server compatible with the RuneScape client https://www.openrs2.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
openrs2/util/src/main/java/dev/openrs2/util/io/PathExtensions.kt

141 lines
3.9 KiB

package dev.openrs2.util.io
import java.io.BufferedWriter
import java.io.OutputStream
import java.nio.channels.FileChannel
import java.nio.charset.Charset
import java.nio.file.CopyOption
import java.nio.file.FileVisitOption
import java.nio.file.Files
import java.nio.file.LinkOption
import java.nio.file.OpenOption
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.nio.file.StandardOpenOption
import java.nio.file.attribute.FileAttribute
fun Path.fsync() {
require(Files.isRegularFile(this) || Files.isDirectory(this))
FileChannel.open(this, StandardOpenOption.READ).use { channel ->
channel.force(true)
}
}
fun Path.recursiveCopy(
destination: Path,
visitOptions: Array<FileVisitOption> = emptyArray(),
copyOptions: Array<CopyOption> = emptyArray()
) {
for (sourceFile in Files.walk(this, *visitOptions)) {
val destinationFile = destination.resolve(this.relativize(sourceFile).toString())
if (Files.isDirectory(sourceFile)) {
Files.createDirectory(destinationFile)
} else {
Files.copy(sourceFile, destinationFile, *copyOptions)
}
}
}
fun Path.recursiveEquals(
other: Path,
linkOptions: Array<LinkOption> = emptyArray(),
openOptions: Array<OpenOption> = emptyArray()
): Boolean {
val list1 = Files.newDirectoryStream(this).use { stream ->
stream.map { this.relativize(it).toString() }.sorted().toList()
}
val list2 = Files.newDirectoryStream(other).use { stream ->
stream.map { other.relativize(it).toString() }.sorted().toList()
}
if (list1 != list2) {
return false
}
for (file in list1) {
val file1 = this.resolve(file)
val file2 = other.resolve(file)
if (Files.isDirectory(file1, *linkOptions)) {
if (!Files.isDirectory(file2, *linkOptions)) {
return false
}
} else {
Files.newInputStream(file1, *openOptions).use { input1 ->
Files.newInputStream(file2, *openOptions).use { input2 ->
if (!input1.contentEquals(input2)) {
return false
}
}
}
}
}
return true
}
inline fun <T> useTempFile(
prefix: String? = null,
suffix: String? = null,
vararg attributes: FileAttribute<*>,
f: (Path) -> T
): T {
val tempFile = Files.createTempFile(prefix, suffix, *attributes)
try {
return f(tempFile)
} finally {
Files.deleteIfExists(tempFile)
}
}
inline fun <T> Path.useTempFile(
prefix: String? = null,
suffix: String? = null,
vararg attributes: FileAttribute<*>,
f: (Path) -> T
): T {
val tempFile = Files.createTempFile(this, prefix, suffix, *attributes)
try {
return f(tempFile)
} finally {
Files.deleteIfExists(tempFile)
}
}
inline fun <T> Path.atomicWrite(f: (Path) -> T): T {
val tempFile = Files.createTempFile(parent, ".$fileName", ".tmp")
try {
val result = f(tempFile)
Files.move(tempFile, this, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
return result
} finally {
Files.deleteIfExists(tempFile)
}
}
inline fun <T> Path.useAtomicBufferedWriter(vararg options: OpenOption, f: (BufferedWriter) -> T): T {
return atomicWrite { path ->
Files.newBufferedWriter(path, *options).use { writer ->
f(writer)
}
}
}
inline fun <T> Path.useAtomicBufferedWriter(cs: Charset, vararg options: OpenOption, f: (BufferedWriter) -> T): T {
return atomicWrite { path ->
Files.newBufferedWriter(path, cs, *options).use { writer ->
f(writer)
}
}
}
inline fun <T> Path.useAtomicOutputStream(vararg options: OpenOption, f: (OutputStream) -> T): T {
return atomicWrite { path ->
Files.newOutputStream(path, *options).use { output ->
f(output)
}
}
}