Remove more java.io usage

This commit is contained in:
FooIbar committed 2024-12-13 11:51:48 +08:00
1 parent 41decf85c9
commit de5d74a1f0
11 files changed
+77 -77

No files matched your search

@@ -16,8 +16,9 @@ import com.hippo.ehviewer.client.data.TagNamespace.Male
import com.hippo.ehviewer.client.data.TagNamespace.Mixed import com.hippo.ehviewer.client.data.TagNamespace.Mixed
import com.hippo.ehviewer.client.data.TagNamespace.Other import com.hippo.ehviewer.client.data.TagNamespace.Other
import com.hippo.ehviewer.client.data.TagNamespace.Parody import com.hippo.ehviewer.client.data.TagNamespace.Parody
import com.hippo.files.inputStream import com.hippo.ehviewer.ui.screen.implicit
import com.hippo.files.outputStream import com.hippo.files.read
import com.hippo.files.write
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -25,12 +26,12 @@ import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import net.devrieze.xmlutil.serialization.kxio.decodeFromSource
import net.devrieze.xmlutil.serialization.kxio.encodeToSink
import nl.adaptivity.xmlutil.XmlDeclMode import nl.adaptivity.xmlutil.XmlDeclMode
import nl.adaptivity.xmlutil.core.XmlVersion import nl.adaptivity.xmlutil.core.XmlVersion
import nl.adaptivity.xmlutil.newWriter
import nl.adaptivity.xmlutil.serialization.XML import nl.adaptivity.xmlutil.serialization.XML
import nl.adaptivity.xmlutil.serialization.XmlElement import nl.adaptivity.xmlutil.serialization.XmlElement
import nl.adaptivity.xmlutil.xmlStreaming
import okio.Path import okio.Path
const val COMIC_INFO_FILE = "ComicInfo.xml" const val COMIC_INFO_FILE = "ComicInfo.xml"
@@ -107,18 +108,14 @@ fun ComicInfo.toSimpleTags() = listOfNotNull(
).flatten().ifEmpty { null } ).flatten().ifEmpty { null }
fun ComicInfo.write(file: Path) { fun ComicInfo.write(file: Path) {
file.outputStream().bufferedWriter().use { file.write {
xmlStreaming.newWriter(it).use { writer -> xml.encodeToSink(this, implicit<ComicInfo>())
xml.encodeToWriter(writer, ComicInfo.serializer(), this)
}
} }
} }
fun readComicInfo(file: Path): ComicInfo? = runCatching { fun readComicInfo(file: Path): ComicInfo? = runCatching {
file.inputStream().bufferedReader().use { file.read {
xmlStreaming.newReader(it).use { reader -> xml.decodeFromSource<ComicInfo>(this)
xml.decodeFromReader(ComicInfo.serializer(), reader)
}
} }
}.getOrNull() }.getOrNull()
@@ -39,6 +39,7 @@ import com.hippo.ehviewer.download.tempDownloadDir
import com.hippo.ehviewer.image.PathSource import com.hippo.ehviewer.image.PathSource
import com.hippo.ehviewer.jni.archiveFdBatch import com.hippo.ehviewer.jni.archiveFdBatch
import com.hippo.ehviewer.util.FileUtils import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.copyTo
import com.hippo.ehviewer.util.sendTo import com.hippo.ehviewer.util.sendTo
import com.hippo.ehviewer.util.sha1 import com.hippo.ehviewer.util.sha1
import com.hippo.files.delete import com.hippo.files.delete
@@ -49,7 +50,6 @@ import com.hippo.files.list
import com.hippo.files.mkdirs import com.hippo.files.mkdirs
import com.hippo.files.moveTo import com.hippo.files.moveTo
import com.hippo.files.openFileDescriptor import com.hippo.files.openFileDescriptor
import com.hippo.files.outputStream
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import io.ktor.client.plugins.onDownload import io.ktor.client.plugins.onDownload
import io.ktor.client.plugins.timeout import io.ktor.client.plugins.timeout
@@ -221,9 +221,7 @@ class SpiderDen(val info: GalleryInfo) {
val url = response.request.url.toString() val url = response.request.url.toString()
val extension = MimeTypeMap.getFileExtensionFromUrl(url).ifEmpty { "jpg" } val extension = MimeTypeMap.getFileExtensionFromUrl(url).ifEmpty { "jpg" }
return saveResponseMeta(index, extension) { outFile -> return saveResponseMeta(index, extension) { outFile ->
outFile.outputStream().use { response.bodyAsChannel().copyTo(outFile)
response.bodyAsChannel().copyTo(it.channel)
}
FileHashRegex.find(url)?.let { FileHashRegex.find(url)?.let {
val expected = it.groupValues[1] val expected = it.groupValues[1]
val actual = outFile.sha1() val actual = outFile.sha1()
@@ -4,8 +4,8 @@ import com.hippo.ehviewer.coil.edit
import com.hippo.ehviewer.coil.read import com.hippo.ehviewer.coil.read
import com.hippo.ehviewer.ktbuilder.diskCache import com.hippo.ehviewer.ktbuilder.diskCache
import com.hippo.ehviewer.legacy.readLegacySpiderInfo import com.hippo.ehviewer.legacy.readLegacySpiderInfo
import com.hippo.files.outputStream
import com.hippo.files.read import com.hippo.files.read
import com.hippo.files.write
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.io.readByteArray import kotlinx.io.readByteArray
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@@ -37,15 +37,13 @@ private val cbor = Cbor {
} }
fun SpiderInfo.write(file: Path) { fun SpiderInfo.write(file: Path) {
file.outputStream().use { file.write { write(cbor.encodeToByteArray(this)) }
it.write(cbor.encodeToByteArray(this))
}
} }
fun SpiderInfo.saveToCache() { fun SpiderInfo.saveToCache() {
runSuspendCatching { runSuspendCatching {
spiderInfoCache.edit(gid.toString()) { spiderInfoCache.edit(gid.toString()) {
data.toFile().writeBytes(cbor.encodeToByteArray(this@saveToCache)) data.write { write(cbor.encodeToByteArray(this@saveToCache)) }
} }
}.onFailure { }.onFailure {
logcat(it) logcat(it)
@@ -67,8 +67,9 @@ import com.hippo.ehviewer.util.requestPermission
import com.hippo.ehviewer.util.toEpochMillis import com.hippo.ehviewer.util.toEpochMillis
import com.hippo.ehviewer.util.toLocalDateTime import com.hippo.ehviewer.util.toLocalDateTime
import com.hippo.files.delete import com.hippo.files.delete
import com.hippo.files.exists
import com.hippo.files.isDirectory import com.hippo.files.isDirectory
import com.hippo.files.outputStream import com.hippo.files.write
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.lang.withUIContext
@@ -89,7 +90,7 @@ private fun removeNoMediaFile(downloadDir: Path) {
} }
private fun ensureNoMediaFile(downloadDir: Path) { private fun ensureNoMediaFile(downloadDir: Path) {
(downloadDir / ".nomedia").outputStream().close() (downloadDir / ".nomedia").apply { if (!exists()) write {} }
} }
private val lck = Mutex() private val lck = Mutex()
@@ -7,7 +7,7 @@ import com.hippo.ehviewer.client.executeAndParseAs
import com.hippo.ehviewer.client.executeSafely import com.hippo.ehviewer.client.executeSafely
import com.hippo.ehviewer.util.copyTo import com.hippo.ehviewer.util.copyTo
import com.hippo.ehviewer.util.ensureSuccess import com.hippo.ehviewer.util.ensureSuccess
import com.hippo.files.outputStream import com.hippo.files.write
import io.ktor.client.plugins.timeout import io.ktor.client.plugins.timeout
import io.ktor.client.request.HttpRequestBuilder import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.header import io.ktor.client.request.header
@@ -18,6 +18,7 @@ import java.util.zip.ZipInputStream
import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.days
import kotlinx.datetime.Clock import kotlinx.datetime.Clock
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import kotlinx.io.asSource
import moe.tarsin.coroutines.runSuspendCatching import moe.tarsin.coroutines.runSuspendCatching
import okio.Path import okio.Path
import tachiyomi.data.release.GithubArtifacts import tachiyomi.data.release.GithubArtifacts
@@ -79,9 +80,7 @@ object AppUpdater {
response.bodyAsChannel().toInputStream().use { stream -> response.bodyAsChannel().toInputStream().use { stream ->
ZipInputStream(stream).use { zip -> ZipInputStream(stream).use { zip ->
zip.nextEntry zip.nextEntry
path.outputStream().use { path.write { transferFrom(zip.asSource()) }
zip.copyTo(it)
}
} }
} }
} else { } else {
@@ -1,35 +1,6 @@
package com.hippo.ehviewer.util package com.hippo.ehviewer.util
import android.os.Build import com.hippo.files.SystemFileSystem
import android.system.Int64Ref
import android.system.Os
import androidx.annotation.RequiresApi
import com.hippo.files.inputStream
import com.hippo.files.openFileDescriptor
import com.hippo.files.outputStream
import eu.kanade.tachiyomi.util.system.logcat
import java.io.FileDescriptor
import okio.Path import okio.Path
@RequiresApi(Build.VERSION_CODES.P) infix fun Path.sendTo(file: Path) = SystemFileSystem.copy(this, file)
private fun sendFileTotally(from: FileDescriptor, to: FileDescriptor): Long = Os.sendfile(to, from, Int64Ref(0), Long.MAX_VALUE)
infix fun Path.sendTo(file: Path): Long {
if (isAtLeastP) {
// sendfile may fail on some devices
try {
return openFileDescriptor("r").use { src ->
file.openFileDescriptor("wt").use { dst ->
sendFileTotally(src.fileDescriptor, dst.fileDescriptor)
}
}
} catch (e: Exception) {
logcat("sendfile", e)
}
}
return inputStream().use { src ->
file.outputStream().use { dst ->
src.channel.transferTo(0, Long.MAX_VALUE, dst.channel)
}
}
}
@@ -15,9 +15,10 @@
*/ */
package com.hippo.ehviewer.util package com.hippo.ehviewer.util
import com.hippo.files.outputStream import com.hippo.files.write
import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.copyTo import io.ktor.utils.io.InternalAPI
import io.ktor.utils.io.rethrowCloseCauseIfNeeded
import java.io.File import java.io.File
import java.util.Locale import java.util.Locale
import kotlin.math.ln import kotlin.math.ln
@@ -125,8 +126,13 @@ object FileUtils {
fun getNameFromFilename(filename: String?) = filename?.substringBeforeLast('.')?.ifEmpty { null } fun getNameFromFilename(filename: String?) = filename?.substringBeforeLast('.')?.ifEmpty { null }
} }
@OptIn(InternalAPI::class)
suspend fun ByteReadChannel.copyTo(file: Path) { suspend fun ByteReadChannel.copyTo(file: Path) {
file.outputStream().use { file.write {
copyTo(it.channel) while (!isClosedForRead) {
transferFrom(readBuffer)
awaitContent()
}
rethrowCloseCauseIfNeeded()
} }
} }
@@ -7,8 +7,13 @@ import android.os.ParcelFileDescriptor
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.provider.DocumentsContract.Document import android.provider.DocumentsContract.Document
import android.provider.MediaStore import android.provider.MediaStore
import android.system.ErrnoException
import android.system.Int64Ref
import android.system.Os
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import androidx.core.database.getLongOrNull import androidx.core.database.getLongOrNull
import kotlinx.io.asSink
import kotlinx.io.asSource
import okio.FileHandle import okio.FileHandle
import okio.FileMetadata import okio.FileMetadata
import okio.FileNotFoundException import okio.FileNotFoundException
@@ -16,8 +21,7 @@ import okio.FileSystem
import okio.IOException import okio.IOException
import okio.Path import okio.Path
import okio.Sink import okio.Sink
import okio.sink import okio.Source
import okio.source
import splitties.init.appCtx import splitties.init.appCtx
class AndroidFileSystem(context: Context) : FileSystem() { class AndroidFileSystem(context: Context) : FileSystem() {
@@ -48,6 +52,26 @@ class AndroidFileSystem(context: Context) : FileSystem() {
TODO("Not yet implemented") TODO("Not yet implemented")
} }
override fun copy(source: Path, target: Path) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
source.openFileDescriptor("r").use { src ->
target.openFileDescriptor("wt").use { dst ->
try {
Os.sendfile(dst.fileDescriptor, src.fileDescriptor, Int64Ref(0), Long.MAX_VALUE)
return
} catch (_: ErrnoException) {}
}
}
}
// Fallback to transferTo if sendfile is not available or fails
source.inputStream().use { src ->
target.outputStream().use { dst ->
src.channel.transferTo(0, Long.MAX_VALUE, dst.channel)
}
}
}
override fun createDirectory(dir: Path, mustCreate: Boolean) { override fun createDirectory(dir: Path, mustCreate: Boolean) {
if (dir.isPhysicalFile()) { if (dir.isPhysicalFile()) {
return physicalFileSystem.createDirectory(dir, mustCreate) return physicalFileSystem.createDirectory(dir, mustCreate)
@@ -177,11 +201,16 @@ class AndroidFileSystem(context: Context) : FileSystem() {
} }
override fun sink(file: Path, mustCreate: Boolean): Sink { override fun sink(file: Path, mustCreate: Boolean): Sink {
if (mustCreate && exists(file)) throw IOException("$file already exists.") TODO("Not yet implemented")
return file.outputStream().sink()
} }
override fun source(file: Path) = file.inputStream().source() override fun source(file: Path): Source {
TODO("Not yet implemented")
}
fun rawSink(file: Path) = file.outputStream().asSink()
fun rawSource(file: Path) = file.inputStream().asSource()
fun openFileDescriptor(path: Path, mode: String): ParcelFileDescriptor { fun openFileDescriptor(path: Path, mode: String): ParcelFileDescriptor {
if (path.isPhysicalFile()) { if (path.isPhysicalFile()) {
@@ -199,6 +228,10 @@ class AndroidFileSystem(context: Context) : FileSystem() {
contentResolver.openFileDescriptor(path.toUri(), mode) contentResolver.openFileDescriptor(path.toUri(), mode)
}.getOrNull() ?: throw FileNotFoundException("Failed to open file: $path") }.getOrNull() ?: throw FileNotFoundException("Failed to open file: $path")
} }
private fun Path.inputStream() = ParcelFileDescriptor.AutoCloseInputStream(openFileDescriptor(this, "r"))
private fun Path.outputStream() = ParcelFileDescriptor.AutoCloseOutputStream(openFileDescriptor(this, "wt"))
} }
private fun Path.isPhysicalFile() = toString().startsWith('/') private fun Path.isPhysicalFile() = toString().startsWith('/')
+3 -8
View File
@@ -2,12 +2,9 @@ package com.hippo.files
import android.content.ContentResolver import android.content.ContentResolver
import android.net.Uri import android.net.Uri
import android.os.ParcelFileDescriptor
import androidx.core.net.toUri import androidx.core.net.toUri
import java.io.FileInputStream import kotlinx.io.Sink
import java.io.FileOutputStream
import kotlinx.io.Source import kotlinx.io.Source
import kotlinx.io.asSource
import kotlinx.io.buffered import kotlinx.io.buffered
import okio.Path import okio.Path
import okio.Path.Companion.toPath import okio.Path.Companion.toPath
@@ -34,11 +31,9 @@ infix fun Path.moveTo(target: Path) = SystemFileSystem.atomicMove(this, target)
fun Path.openFileDescriptor(mode: String) = SystemFileSystem.openFileDescriptor(this, mode) fun Path.openFileDescriptor(mode: String) = SystemFileSystem.openFileDescriptor(this, mode)
fun Path.inputStream(): FileInputStream = ParcelFileDescriptor.AutoCloseInputStream(SystemFileSystem.openFileDescriptor(this, "r")) inline fun <T> Path.read(f: Source.() -> T) = SystemFileSystem.rawSource(this).buffered().use(f)
fun Path.outputStream(): FileOutputStream = ParcelFileDescriptor.AutoCloseOutputStream(SystemFileSystem.openFileDescriptor(this, "wt")) inline fun <T> Path.write(f: Sink.() -> T) = SystemFileSystem.rawSink(this).buffered().use(f)
inline fun <T> Path.read(f: Source.() -> T) = inputStream().asSource().buffered().use(f)
fun Path.toUri(): Uri { fun Path.toUri(): Uri {
val str = toString() val str = toString()
+3 -2
View File
@@ -30,7 +30,7 @@ okhttp = "5.0.0-alpha.14"
okio = "3.9.1" okio = "3.9.1"
splitties = "3.0.0" splitties = "3.0.0"
telephoto = "0.14.0" telephoto = "0.14.0"
xmlutil = "0.90.3" xmlutil = "0.90.4-SNAPSHOT"
junit = "1.2.1" junit = "1.2.1"
uiautomator = "2.4.0-alpha01" uiautomator = "2.4.0-alpha01"
benchmark = "1.4.0-alpha06" benchmark = "1.4.0-alpha06"
@@ -112,6 +112,7 @@ serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-jso
serialization-json-io = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-io", version.ref = "kotlinx-serialization" } serialization-json-io = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-io", version.ref = "kotlinx-serialization" }
serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization", version.ref = "xmlutil" } serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization", version.ref = "xmlutil" }
serialization-xml-io = { module = "io.github.pdvrieze.xmlutil:serialization-io", version.ref = "xmlutil" }
splitties-appctx = { module = "com.louiscad.splitties:splitties-appctx", version.ref = "splitties" } splitties-appctx = { module = "com.louiscad.splitties:splitties-appctx", version.ref = "splitties" }
splitties-arch-room = { module = "com.louiscad.splitties:splitties-arch-room", version.ref = "splitties" } splitties-arch-room = { module = "com.louiscad.splitties:splitties-arch-room", version.ref = "splitties" }
@@ -129,7 +130,7 @@ androidx-profileinstaller = { module = "androidx.profileinstaller:profileinstall
arrow = ["arrow-fx-coroutines", "arrow-functions", "arrow-resilience"] arrow = ["arrow-fx-coroutines", "arrow-functions", "arrow-resilience"]
coil = ["coil-compose", "coil-gif", "coil-network"] coil = ["coil-compose", "coil-gif", "coil-network"]
compose = ["compose-foundation", "compose-material-icons-extended", "compose-material3", "compose-material3-adaptive", "compose-ui-util"] compose = ["compose-foundation", "compose-material-icons-extended", "compose-material3", "compose-material3-adaptive", "compose-ui-util"]
kotlinx-serialization = ["serialization-cbor", "serialization-json", "serialization-json-io", "serialization-xml"] kotlinx-serialization = ["serialization-cbor", "serialization-json", "serialization-json-io", "serialization-xml", "serialization-xml-io"]
splitties = ["splitties-appctx", "splitties-arch-room", "splitties-preferences", "splitties-systemservices"] splitties = ["splitties-appctx", "splitties-arch-room", "splitties-preferences", "splitties-systemservices"]
[plugins] [plugins]
+1
View File
@@ -11,6 +11,7 @@ dependencyResolutionManagement {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
} }
} }