Skip to content

Instantly share code, notes, and snippets.

@alex8224
Last active September 7, 2017 11:27
Show Gist options
  • Save alex8224/e4204fec4ee7a3925a7385c0728a05cf to your computer and use it in GitHub Desktop.
Save alex8224/e4204fec4ee7a3925a7385c0728a05cf to your computer and use it in GitHub Desktop.
resume download use kotlin
import java.io.*
import java.net.URL
import java.net.HttpURLConnection as http
data class Response(val status: Int=200, var header: Map<String, List<String>>, var stream: InputStream)
object Request {
private fun method(method:String, url: String, header: Map<String, String>, followRedirect:Boolean=true): Pair<Response, http> {
val client = URL(url).openConnection() as http
client.requestMethod = method
client.instanceFollowRedirects = followRedirect
client.addHeaders(header)
val respHeader = client.headerFields.filter { m->m.key != null }
return Pair(Response(client.responseCode, respHeader, client.inputStream), client)
}
fun get(url: String, header:Map<String, String>): Pair<Response,http> {
return method("GET", url, header)
}
fun range(url: String, header:Map<String, String>, start:Int=0, end:Int=0): Pair<Response,http> {
val endIndex = if (end == 0) "" else end
val rangeStr = "bytes=%d-%s".format(start, endIndex)
val mutableMap = header as MutableMap
mutableMap.put("Range", rangeStr)
return method("GET", url, header)
}
fun head(url: String, header:Map<String, String>): Pair<Response,http> {
return method("HEAD", url, header)
}
}
val headers = mutableMapOf(
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
"Accept" to "*",
"Range" to "bytes=0-1024",
"Connection" to "keep-alive",
"Referer" to "",
"Accept-Encoding" to "en;q=0.4,en-US;q=0.2",
"Accept-Encoding" to "gzip, deflate"
)
val name = "test"
fun getLength(url:String): Int? {
val (headResp, client) = Request.head(url, headers)
val status = headResp.status
if (status != 200) {
println("failed!")
}
client.close()
return headResp.header.get("Content-Length")?.get(0)?.toInt()
}
fun downloadFile(url:String) {
//获取文件信息,恢复断点
val fileInfo = findFile(name)
if (fileInfo == null) {
println("info file not found")
return
}
val (resp, client) = Request.range(url, headers, fileInfo!!.offset!!)
when(resp.status) {
200,206 -> {
writeFile(client.inputStream, name, fileInfo!!.offset!!, fun (bytes: Int){
println(bytes)
val sourceSize = fileInfo.offset!!.plus(bytes)
fileInfo.offset = sourceSize
writeFileInfo(name, fileInfo.size, sourceSize)
})
}
else-> println("download failed!")
}
}
fun main(args:Array<String>) {
val url = ""
var fileInfo = findFile(name)
if(fileInfo == null) {
val vSize = getLength(url)
writeFileInfo(name, vSize, 0)
}
downloadFile(url)
}
fun http.addHeaders(headers:Map<String,String>) {
headers.forEach { k, v -> this.addRequestProperty(k, v) }
}
fun http.close() {
this.disconnect()
}
fun writeFile(stream: InputStream, name:String, offset:Int=0, callback:(bytes:Int)->Unit={}) {
val buff = ByteArray(65535)
val accessFile = RandomAccessFile(File(name), "rw")
val contentLength = 0
accessFile.seek(offset.toLong())
accessFile.use {
var contentLength = 0
while (true) {
val len = stream.read(buff)
if (len == -1) {
println("exited!")
break
}
contentLength = contentLength + len
it.write(buff, 0, len)
callback(len)
}
}
println("%s length is %d".format(name, contentLength))
}
fun findFile(name:String):FileInfo? {
val infoFileName = "%s.info".format(name)
val infoFile = File(infoFileName)
if (infoFile.exists()) {
val fileInfo = FileInfo()
val textInfo = infoFile.readText().split("\n")
textInfo.forEach { it ->
val pair = it.split("=")
when(pair[0]) {
"name" -> fileInfo.name = pair[1]
"size" -> fileInfo.size = pair[1].toInt()
"offset" -> fileInfo.offset = pair[1].toInt()
"ok" -> fileInfo.ok = pair[1].toBoolean()
}
}
return fileInfo
}
return null
}
fun writeFileInfo(name:String, size:Int?, offset: Int):FileInfo {
val infPath = "%s.info".format(name)
val ok = offset >0 && offset == size
val infContent= "name=%s\nsize=%d\noffset=%d\nok=%b".format(name, size, offset, ok)
File(infPath).writeText(infContent)
return FileInfo(name, size)
}
data class FileInfo(var name:String?=null, var size:Int?=0, var offset: Int?=0, var ok:Boolean?=false)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment