我有一个通用的抽象方法,该方法获取输入流(可以来自网络套接字,也可以来自本地存储中的文件),然后将数据保存在磁盘上。
下面是该函数的一小段:
fun saveToFile(data: InputStream, fileDestination: File) {
val bytesWritten = Files.copy(data, fileDestination.toPath(), StandardCopyOption.REPLACE_EXISTING)
println("$bytesWritten bytes were saved at ${fileDestination.absolutePath}")
}
在处理/方法进行过程中,是否可以测量将数据保存在磁盘上的速度/速率?例如,是否有可能调用返回速率/速度或更新保存该数据的对象的函数?
如果我自己使用InputStream / OutputStream来实现,那么我可能会遇到以下类似情况:
fun saveData(data: InputStream, fileDestination: File, measureSpeed : (Statistics) -> Unit = { }) {
val outputStream = fileDestination.outputStream()
val maxBufferSize = 1024
val totalAmountData = data.available()
var totalBytesWritten = 0
var bytesWriteNextIteration: Int // amount of bytes that will be sent in only one write call
val statistics = Statistics(amountSent = 0, lastWriteBytes = 0, lastWriteTime = 1)
while (totalBytesWritten < totalAmountData) {
bytesWriteNextIteration = totalAmountData - totalBytesWritten
if (bytesWriteNextIteration > maxBufferSize) {
bytesWriteNextIteration = maxBufferSize
}
val bytes = ByteArray(bytesWriteNextIteration)
val nano = measureNanoTime {
outputStream.write(bytes)
}
statistics.amountSent = totalBytesWritten.toLong()
statistics.lastWriteBytes = bytesWriteNextIteration.toLong()
statistics.lastWriteTime = nano
measureSpeed(statistics)
totalBytesWritten += bytesWriteNextIteration
}
outputStream.flush()
outputStream.close()
}
data class Statistics(var amountSent: Long, var lastWriteBytes: Long, var lastWriteTime: Long)
并使用measureSpeed
方法来计算复印/传输速率。
答案 0 :(得分:0)
由于我没有找到任何内置的东西,因此执行要求的最简单方法是“重载”所需的Files.copy
方法并调用该函数。
重载方法可能类似于以下内容:
private val BUFFER_SIZE = 8192
@Throws(IOException::class)
private fun copy(source: InputStream, sink: OutputStream, networkStatistics: NetworkStatistics, measureSpeed : (NetworkStatistics) -> Unit = { }): Long {
var nread = 0L
val buf = ByteArray(BUFFER_SIZE)
var n: Int
n = source.read(buf)
while (n > 0) {
val nano = measureNanoTime {
sink.write(buf, 0, n)
nread += n.toLong()
n = source.read(buf)
}
networkStatistics.amountSent = nread
networkStatistics.lastPacketBytes = n.toLong()
networkStatistics.lastPacketTime = nano
measureSpeed(networkStatistics)
}
return nread
}
@Throws(IOException::class)
fun copy(`in`: InputStream, target: Path, networkStatistics: NetworkStatistics, measureSpeed : (NetworkStatistics) -> Unit = { }, vararg options: CopyOption ): Long {
// ensure not null before opening file
Objects.requireNonNull(`in`)
// check for REPLACE_EXISTING
var replaceExisting = false
for (opt in options) {
if (opt === StandardCopyOption.REPLACE_EXISTING) {
replaceExisting = true
} else {
if (opt == null) {
throw NullPointerException("options contains 'null'")
} else {
throw UnsupportedOperationException(opt.toString() + " not supported")
}
}
}
// attempt to delete an existing file
var se: SecurityException? = null
if (replaceExisting) {
try {
Files.deleteIfExists(target)
} catch (x: SecurityException) {
se = x
}
}
// attempt to create target file. If it fails with
// FileAlreadyExistsException then it may be because the security
// manager prevented us from deleting the file, in which case we just
// throw the SecurityException.
val ostream: OutputStream
try {
ostream = Files.newOutputStream(target, StandardOpenOption.CREATE_NEW,
StandardOpenOption.WRITE)
} catch (x: FileAlreadyExistsException) {
if (se != null)
throw se
// someone else won the race and created the file
throw x
}
// do the copy
ostream.use { out -> return copy(`in`, out, networkStatistics, measureSpeed = { networkStatistics -> measureSpeed(networkStatistics) }) }
}
,它将被称为:
val statistics = NetworkStatistics(responseShouldBe, 0, 0, 1)
copy(inputStream, file.toPath(), statistics, { it: NetworkStatistics -> measureSpeed(it) }, StandardCopyOption.REPLACE_EXISTING)
private fun measureSpeed(stats: NetworkStatistics) {
val a = stats.lastPacketBytes
val b = stats.lastPacketTime
val miliseconds = b.toDouble() / 1000
val seconds = miliseconds / 1000
println("$a per ($seconds seconds) or ($miliseconds milisecs) or ($b nanosecs) -- ${(a.toDouble()/(1024*1024))/seconds} MB/seconds")
}