Skip to content

Commit

Permalink
[file-writing] Add helpers for writing files
Browse files Browse the repository at this point in the history
  • Loading branch information
lailabecker committed Sep 19, 2024
1 parent 6476a23 commit 0bab855
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package ch.dreipol.dreimultiplatform

import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.util.AtomicFile
import java.io.DataOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStreamWriter
import java.nio.file.Files
import kotlin.streams.toList


actual typealias FileIdentifier = File

Expand Down Expand Up @@ -45,4 +49,56 @@ actual object FileManager {
actual fun byteArrayFrom(file: FileIdentifier): ByteArray? = file.readBytes()

actual fun fileIdentifierFromPath(path: String): FileIdentifier? = File(path)

actual fun write(data: ByteArray, toFile: FileIdentifier, atomically: Boolean): Boolean =
if (atomically) {
AtomicFile(toFile).write(data)
} else {
runCatching {
toFile.writeBytes(data)
}.isSuccess
}

actual fun write(string: String, toFile: FileIdentifier, atomically: Boolean): Boolean =
if (atomically) {
AtomicFile(toFile).write(string)
} else {
runCatching {
toFile.writeText(string)
}.isSuccess
}

private fun AtomicFile.write(data: ByteArray): Boolean {
var dataOutput: DataOutputStream? = null
var outputStream: FileOutputStream? = null
try {
outputStream = startWrite()
dataOutput = DataOutputStream(outputStream) // Wrapper stream
dataOutput.write(data)
finishWrite(outputStream) // Pass wrapper stream
return true
} catch (_: Throwable) {
outputStream?.let { failWrite(it) }
return false
} finally {
dataOutput?.close()
}
}

private fun AtomicFile.write(string: String): Boolean {
var dataOutput: OutputStreamWriter? = null
var outputStream: FileOutputStream? = null
try {
outputStream = startWrite()
dataOutput = OutputStreamWriter(outputStream) // Wrapper stream
dataOutput.write(string)
finishWrite(outputStream) // Pass wrapper stream
return true
} catch (_: Throwable) {
outputStream?.let { failWrite(it) }
return false
} finally {
dataOutput?.close()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ expect object FileManager {
fun byteArrayFrom(file: FileIdentifier): ByteArray?

fun fileIdentifierFromPath(path: String): FileIdentifier?

fun write(data: ByteArray, toFile: FileIdentifier, atomically: Boolean): Boolean

fun write(string: String, toFile: FileIdentifier, atomically: Boolean): Boolean
}
15 changes: 15 additions & 0 deletions src/iosMain/kotlin/ch/dreipol/dreimultiplatform/FileManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr
import kotlinx.cinterop.value
import platform.Foundation.NSCachesDirectory
import platform.Foundation.NSData
import platform.Foundation.NSError
import platform.Foundation.NSFileManager
import platform.Foundation.NSSearchPathDirectory
import platform.Foundation.NSSearchPathForDirectoriesInDomains
import platform.Foundation.NSString
import platform.Foundation.NSURL
import platform.Foundation.NSUTF8StringEncoding
import platform.Foundation.NSUserDomainMask
import platform.Foundation.URLByAppendingPathComponent
import platform.Foundation.dataWithContentsOfURL
import platform.Foundation.lastPathComponent
import platform.Foundation.stringWithContentsOfURL
import platform.Foundation.stringWithString
import platform.Foundation.writeToFile

@kotlinx.cinterop.ExperimentalForeignApi
typealias ErrorPointer = CPointer<ObjCObjectVar<NSError?>>
Expand Down Expand Up @@ -70,6 +76,15 @@ actual object FileManager {
actual fun byteArrayFrom(file: FileIdentifier): ByteArray? = NSData.dataWithContentsOfURL(file.url)?.toByteArray()

actual fun fileIdentifierFromPath(path: String): FileIdentifier? = NSURL.fileURLWithPath(path).toFileIdentifier()

actual fun write(data: ByteArray, toFile: FileIdentifier, atomically: Boolean): Boolean {
val path = toFile.filePath ?: return false
return data.toNSData().writeToFile(path, atomically)
}

@OptIn(ExperimentalStdlibApi::class)
actual fun write(string: String, toFile: FileIdentifier, atomically: Boolean): Boolean =
write(string.hexToByteArray(), toFile, atomically)
}

@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
Expand Down

0 comments on commit 0bab855

Please sign in to comment.