返回 CodeWhale
PetLiveFile.kt
根目录 / pet / android / src / main / kotlin / codewhale / pet / PetLiveFile.kt
1 package codewhale.pet
2
3 import android.content.ContentResolver
4 import android.net.Uri
5 import android.os.CancellationSignal
6 import android.os.ParcelFileDescriptor
7 import java.nio.ByteBuffer
8
9 /** Read only the tail of a user-selected, seekable local document. Reads stay
10 * off the world worker; cancellation closes the descriptor and provider request.
11 * Packet validation, sequence restarts and freshness belong to the shared core. */
12 class PetLiveFile(private val resolver: ContentResolver, private val uri: Uri) : AutoCloseable {
13 private val cancellation = CancellationSignal()
14 @Volatile private var descriptor: ParcelFileDescriptor? = null
15 init { require(uri.scheme == "content") { "Choose a local document through the file picker." } }
16 fun readTail(): String {
17 val opened = resolver.openFileDescriptor(uri, "r", cancellation) ?: error("The local tape could not be opened.")
18 descriptor = opened
19 try {
20 cancellation.throwIfCanceled()
21 return ParcelFileDescriptor.AutoCloseInputStream(opened).use { stream ->
22 val channel = stream.channel
23 val size = channel.size()
24 val length = minOf(size, 262_144L).toInt()
25 channel.position(size - length)
26 val buffer = ByteBuffer.allocate(length)
27 while (buffer.hasRemaining() && channel.read(buffer) > 0) cancellation.throwIfCanceled()
28 String(buffer.array(), 0, buffer.position(), Charsets.UTF_8)
29 }
30 } finally { descriptor = null; opened.close() }
31 }
32 override fun close() {
33 cancellation.cancel()
34 runCatching { descriptor?.close() }
35 }
36 }
37
37 lines Plain Text