mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 03:36:47 -04:00
Made files opened in read mode seekable more reliably.
This commit is contained in:
parent
bbe80bc5de
commit
d0d4f502ba
@ -94,7 +94,7 @@ trait Buffered extends OutputStreamFileSystem {
|
|||||||
FileUtils.deleteQuietly(childFile)
|
FileUtils.deleteQuietly(childFile)
|
||||||
childFile.createNewFile()
|
childFile.createNewFile()
|
||||||
val out = new io.FileOutputStream(childFile).getChannel
|
val out = new io.FileOutputStream(childFile).getChannel
|
||||||
val in = java.nio.channels.Channels.newChannel(openInputStream(childPath).get)
|
val in = openInputChannel(childPath).get
|
||||||
out.transferFrom(in, 0, Long.MaxValue)
|
out.transferFrom(in, 0, Long.MaxValue)
|
||||||
out.close()
|
out.close()
|
||||||
in.close()
|
in.close()
|
||||||
|
@ -25,8 +25,8 @@ class CC15FileSystem(val mount: IMount) extends InputStreamFileSystem {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
protected def openInputStream(path: String) = try {
|
protected def openInputChannel(path: String) = try {
|
||||||
Some(mount.openForRead(path))
|
Some(new InputFileChannel(mount.openForRead(path)))
|
||||||
} catch {
|
} catch {
|
||||||
case _: Throwable => None
|
case _: Throwable => None
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ class CC16FileSystem(val mount: IMount) extends InputStreamFileSystem {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
protected def openInputStream(path: String) = try {
|
protected def openInputChannel(path: String) = try {
|
||||||
Some(mount.openForRead(path))
|
Some(new InputFileChannel(mount.openForRead(path)))
|
||||||
} catch {
|
} catch {
|
||||||
case _: Throwable => None
|
case _: Throwable => None
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package li.cil.oc.server.fs
|
package li.cil.oc.server.fs
|
||||||
|
|
||||||
import java.io
|
import java.io
|
||||||
|
import java.nio.channels.SeekableByteChannel
|
||||||
|
|
||||||
trait FileInputStreamFileSystem extends InputStreamFileSystem {
|
trait FileInputStreamFileSystem extends InputStreamFileSystem {
|
||||||
protected val root: io.File
|
protected val root: io.File
|
||||||
@ -43,6 +44,6 @@ trait FileInputStreamFileSystem extends InputStreamFileSystem {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override protected def openInputStream(path: String): Option[io.InputStream] =
|
override protected def openInputChannel(path: String): Option[SeekableByteChannel] =
|
||||||
Some(new io.FileInputStream(new io.File(root, path)))
|
Some(new io.RandomAccessFile(new io.File(root, path), "r").getChannel)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package li.cil.oc.server.fs
|
package li.cil.oc.server.fs
|
||||||
|
|
||||||
import java.io.{FileNotFoundException, IOException, InputStream}
|
import java.io.{FileNotFoundException, IOException}
|
||||||
import li.cil.oc.api
|
import li.cil.oc.api
|
||||||
import li.cil.oc.api.fs.Mode
|
import li.cil.oc.api.fs.Mode
|
||||||
import net.minecraft.nbt.{NBTTagList, NBTTagCompound}
|
import net.minecraft.nbt.{NBTTagList, NBTTagCompound}
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
import java.nio.channels.SeekableByteChannel
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
trait InputStreamFileSystem extends api.fs.FileSystem {
|
trait InputStreamFileSystem extends api.fs.FileSystem {
|
||||||
private val handles = mutable.Map.empty[Int, Handle]
|
private val handles = mutable.Map.empty[Int, Handle]
|
||||||
@ -25,9 +27,9 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
|
|||||||
|
|
||||||
override def open(path: String, mode: Mode) = this.synchronized(if (mode == Mode.Read && exists(path) && !isDirectory(path)) {
|
override def open(path: String, mode: Mode) = this.synchronized(if (mode == Mode.Read && exists(path) && !isDirectory(path)) {
|
||||||
val handle = Iterator.continually((Math.random() * Int.MaxValue).toInt + 1).filterNot(handles.contains).next()
|
val handle = Iterator.continually((Math.random() * Int.MaxValue).toInt + 1).filterNot(handles.contains).next()
|
||||||
openInputStream(path) match {
|
openInputChannel(path) match {
|
||||||
case Some(stream) =>
|
case Some(channel) =>
|
||||||
handles += handle -> new Handle(this, handle, path, stream)
|
handles += handle -> new Handle(this, handle, path, channel)
|
||||||
handle
|
handle
|
||||||
case _ => throw new FileNotFoundException()
|
case _ => throw new FileNotFoundException()
|
||||||
}
|
}
|
||||||
@ -49,10 +51,10 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
|
|||||||
val handle = handleNbt.getInteger("handle")
|
val handle = handleNbt.getInteger("handle")
|
||||||
val path = handleNbt.getString("path")
|
val path = handleNbt.getString("path")
|
||||||
val position = handleNbt.getLong("position")
|
val position = handleNbt.getLong("position")
|
||||||
openInputStream(path) match {
|
openInputChannel(path) match {
|
||||||
case Some(stream) =>
|
case Some(channel) =>
|
||||||
val fileHandle = new Handle(this, handle, path, stream)
|
val fileHandle = new Handle(this, handle, path, channel)
|
||||||
fileHandle.position = stream.skip(position) // May be != position if the file changed since we saved.
|
channel.position(position)
|
||||||
handles += handle -> fileHandle
|
handles += handle -> fileHandle
|
||||||
case _ => // The source file seems to have disappeared since last time.
|
case _ => // The source file seems to have disappeared since last time.
|
||||||
}
|
}
|
||||||
@ -62,7 +64,7 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
|
|||||||
override def save(nbt: NBTTagCompound) = this.synchronized {
|
override def save(nbt: NBTTagCompound) = this.synchronized {
|
||||||
val handlesNbt = new NBTTagList()
|
val handlesNbt = new NBTTagList()
|
||||||
for (file <- handles.values) {
|
for (file <- handles.values) {
|
||||||
assert(!file.isClosed)
|
assert(file.channel.isOpen)
|
||||||
val handleNbt = new NBTTagCompound()
|
val handleNbt = new NBTTagCompound()
|
||||||
handleNbt.setInteger("handle", file.handle)
|
handleNbt.setInteger("handle", file.handle)
|
||||||
handleNbt.setString("path", file.path)
|
handleNbt.setString("path", file.path)
|
||||||
@ -74,33 +76,65 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
protected def openInputStream(path: String): Option[InputStream]
|
protected def openInputChannel(path: String): Option[SeekableByteChannel]
|
||||||
|
|
||||||
|
protected class InputFileChannel(val inputStream: java.io.InputStream) extends SeekableByteChannel {
|
||||||
|
var isOpen = true
|
||||||
|
|
||||||
|
private var position_ = 0L
|
||||||
|
|
||||||
|
override def close() = inputStream.close()
|
||||||
|
|
||||||
|
override def truncate(size: Long) = throw new java.io.IOException()
|
||||||
|
|
||||||
|
override def size() = inputStream.available()
|
||||||
|
|
||||||
|
override def position(newPosition: Long) = {
|
||||||
|
inputStream.reset()
|
||||||
|
position_ = inputStream.skip(newPosition)
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
override def position = position_
|
||||||
|
|
||||||
|
override def write(src: ByteBuffer) = throw new java.io.IOException()
|
||||||
|
|
||||||
|
override def read(dst: ByteBuffer): Int = {
|
||||||
|
if (dst.hasArray) {
|
||||||
|
inputStream.read(dst.array())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val count = dst.limit - dst.position
|
||||||
|
for (i <- 0 until count) {
|
||||||
|
inputStream.read match {
|
||||||
|
case -1 => return i
|
||||||
|
case b => dst.put(b.toByte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val stream: InputStream) extends api.fs.Handle {
|
private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val channel: SeekableByteChannel) extends api.fs.Handle {
|
||||||
var isClosed = false
|
override def position = channel.position
|
||||||
var position = 0L
|
|
||||||
|
|
||||||
override def length = owner.size(path)
|
override def length = owner.size(path)
|
||||||
|
|
||||||
override def close() = if (!isClosed) {
|
override def close() = if (channel.isOpen) {
|
||||||
isClosed = true
|
|
||||||
owner.handles -= handle
|
owner.handles -= handle
|
||||||
stream.close()
|
channel.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def read(into: Array[Byte]) = {
|
override def read(into: Array[Byte]) = {
|
||||||
val read = stream.read(into)
|
channel.read(ByteBuffer.wrap(into))
|
||||||
if (read >= 0)
|
|
||||||
position += read
|
|
||||||
read
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override def seek(to: Long) = {
|
override def seek(to: Long) = {
|
||||||
stream.reset()
|
channel.position(to)
|
||||||
position = stream.skip(to)
|
channel.position
|
||||||
position
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override def write(value: Array[Byte]) = throw new IOException("bad file descriptor")
|
override def write(value: Array[Byte]) = throw new IOException("bad file descriptor")
|
||||||
|
@ -97,9 +97,9 @@ trait VirtualFileSystem extends OutputStreamFileSystem {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
protected def openInputStream(path: String) =
|
protected def openInputChannel(path: String) =
|
||||||
root.get(segments(path)) match {
|
root.get(segments(path)) match {
|
||||||
case Some(obj: VirtualFile) => obj.openInputStream()
|
case Some(obj: VirtualFile) => obj.openInputStream().map(new InputFileChannel(_))
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ class ZipFileInputStreamFileSystem(private val archive: ArchiveDirectory) extend
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override protected def openInputStream(path: String) = ZipFileInputStreamFileSystem.synchronized {
|
override protected def openInputChannel(path: String) = ZipFileInputStreamFileSystem.synchronized {
|
||||||
entry(path).map(_.openStream())
|
entry(path).map(entry => new InputFileChannel(entry.openStream()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
Loading…
x
Reference in New Issue
Block a user