使用Kotlin 实现多协程同时下载文件,充分利用IO
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONObject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.runBlocking
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okio.*
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.*
import java.util.zip.ZipFile
import kotlin.collections.HashMap
import kotlin.collections.HashSet
/**
* 模拟登录
*/
fun login() : Flow<JSONObject>{
return flow {
val form = FormBody.Builder()
form.add("user.phone", "18507051259")
form.add("user.password", "123456")
form.add("deviceType", "android")
form.add("app_pkg_name", "com.mytian.appstore.rz")
form.add("app_channel", "mytian")
form.add("client_version", "82")
emit(
JSON.parseObject(
OkHttpClient().newCall(
Request
.Builder().url("http://www.dsadsdsad.com.cn/dasds/userAction_login.do")
.post(form.build()).build()
).execute().body?.string()
)
)
}
}
fun loadListInfo(uid: String, token: String, classType: String) : Flow<JSONObject>{
return flow {
listOf("100","101","102","103","104","105","106","111","119","117","601","701").forEach {
val form = FormBody.Builder()
form.add("uid", uid)
form.add("token", token)
form.add("typeId", it)
form.add("deviceType", "android")
form.add("deviceTypes", "android")
form.add("app_pkg_name", "com.mytian.appstore.rz")
form.add("appNames", "com.mytian.appstore.rz")
form.add("app_channel", "mytian")
form.add("client_version", "125")
form.add("versions", "125")
form.add("channels", "mytian")
form.add("clazzRecord", "[]")
form.add("currentPage", "1")
form.add("pageSize", "156")
emit(
JSON.parseObject(
OkHttpClient().newCall(
Request
.Builder().url("https://cloud.dsdas.com:7776/clazz/getClassList")
.post(form.build()).build()
).execute().body?.string()
)
)
}
}
}
fun downloadRes(downloadUrl:String,id:String) {
println("download begin $id")
OkHttpClient().newCall(Request.Builder().get().url(downloadUrl).build())
.execute().also {
if (it.isSuccessful) {
var sink = File("D:\\cocos2d"+File.separator+id +".zip")
.sink().buffer()
it.body?.source()?.readAll(sink)
sink.flush()
it.body?.close()
sink.close()
println("download end $id")
}
}
}
fun downloadPre(info: JSONObject,infoMap:HashMap<String,String>) {
downloadRes(info["resUrl"].toString(), info["pkgName"].toString())
var gzipOut = ByteArrayOutputStream()
gzipOut.sink().gzip().buffer().write(JSON.toJSONBytes(info)).flush()
var gzipInfo = Base64.getEncoder().encodeToString(gzipOut.toByteArray())
infoMap[info["pkgName"].toString()] = gzipInfo
println("$gzipInfo")
gzipOut.close()
}
fun unZip(zipFile: File, targetDir: File) {
runBlocking {
targetDir.apply {
if (!exists()) {
mkdirs()
}
}
ZipFile(zipFile).also {zip ->
zip.entries().run {
while (hasMoreElements()) {
nextElement().also { entry->
if (entry.isDirectory) {
File("${targetDir.absoluteFile}${File.separator}${entry.name}").run {
if (!exists()) {
mkdirs()
}
}
} else {
async(Dispatchers.IO) {
var sink =
File("${targetDir.absoluteFile}${File.separator}${entry.name}").sink().buffer()
var source =
zip.getInputStream(entry).source().buffer()
source.readAll(sink)
sink.flush()
source.close()
sink.close()
}
}
}
}
}
}
}
}
fun main(args: Array<String>) {
var begin = System.currentTimeMillis()
runBlocking {
File("D:\\cocos2d${File.separator}").listFiles().forEach {
if (it.absolutePath.endsWith(".zip")) {
println(it)
async (Dispatchers.IO){
unZip(
it,
File(it.absolutePath.replace(".zip", ""))
)
}
}
}
}
println(System.currentTimeMillis() - begin)
var infoMap:HashMap<String,String> = HashMap()
var commonDownloadM:HashSet<String> = HashSet();
runBlocking {
async(Dispatchers.IO) {
login().collect {
loadListInfo(
(it["info"] as JSONObject)["uid"].toString(), (it["info"] as JSONObject)["token"].toString()
,"100").collect {
async (Dispatchers.IO){
async(Dispatchers.IO) {
var commonList = ((it["info"] as JSONObject)["commonList"] as JSONArray)
if (commonList.size > 0) {
synchronized(commonDownloadM) {
if (!commonDownloadM.contains((commonList[0] as JSONObject)["pkgName"])) {
commonDownloadM.add((commonList[0] as JSONObject)["pkgName"] as String)
async(Dispatchers.IO) {
downloadPre(commonList[0] as JSONObject, infoMap)
}
}
if (commonList.size > 1) {
if (!commonDownloadM.contains((commonList[1] as JSONObject)["pkgName"])) {
commonDownloadM.add((commonList[1] as JSONObject)["pkgName"] as String)
async(Dispatchers.IO) {
downloadPre(commonList[1] as JSONObject, infoMap)
}
}
}
}
}
downloadPre(((it["info"] as JSONObject)["classList"] as JSONArray)[0] as JSONObject,infoMap)
}
}
}
}
}
}
println(infoMap)
var dirMap = HashMap<String, HashSet<String>>()
dirMap["Rz"] = HashSet<String>().also {
it.add("com.mytian.l00lz001")
it.add("com.mytian.common.ph")
it.add("com.mytian.common")
}
dirMap["En"] = HashSet<String>().also {
it.add("com.mytian.l00ne001")
it.add("com.mytian.common.ph")
it.add("com.mytian.common")
}
dirMap["Ma"] = HashSet<String>().also {
it.add("com.mytian.l00ma001")
it.add("com.mytian.common.ph")
it.add("com.mytian.common")
}
dirMap["Lo"] = HashSet<String>().also {
it.add("com.mytian.l00lo001")
it.add("com.mytian.common.ph")
it.add("com.mytian.common")
}
dirMap["Xz"] = HashSet<String>().also {
it.add("com.mytian.l00xz001")
it.add("com.mytian.common.ph")
it.add("com.mytian.common")
}
dirMap["Ph"] = HashSet<String>().also {
it.add("com.mytian.l00ph001")
it.add("com.mytian.common.ph")
it.add("com.mytian.common")
}
dirMap["Py"] = HashSet<String>().also {
it.add("com.mytian.l00py001")
it.add("com.mytian.common.ph")
it.add("com.mytian.common")
}
runBlocking {
dirMap.forEach { (t, u) ->
async (Dispatchers.IO){
File("D:\\cocos2d${File.separator}${t}").apply {
if (exists() || mkdirs()) {
var properties = Properties()
u.forEach { item ->
var source = File("D:\\cocos2d${File.separator}$item.zip").source().buffer()
var sink = File(
"D:\\cocos2d${File.separator}${t}${File.separator}${
if ("com.mytian.common.ph" == item) "commonUnity" else item.split(".").last()
}.zip"
).sink().buffer()
source.readAll(sink)
source.close()
sink.flush()
sink.close()
properties[if ("com.mytian.common.ph" == item) "commonUnity" else item.split(".").last()] =
infoMap[item]
}
var outputStream = FileOutputStream( File("D:\\cocos2d${File.separator}${t}${File.separator}info.xml"))
properties.storeToXML(outputStream,null)
outputStream.flush()
outputStream.close()
}
}
}
}
}
}
Kotllin协程解压文件 14个文件 解压耗时1412ms