kotlin 中的文件字节错误。如何正确转移?

File byte error in kotlin. How to transfer correctly?

我想用tcp客户端传输文件到服务器,但是图像文件出错了。

我的客户端代码是

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream
import org.msgpack.core.MessageBufferPacker
import org.msgpack.core.MessagePack
import org.msgpack.core.MessageUnpacker
import java.io.*
import java.net.Socket
import java.util.*

fun main(args: Array<String>) {
    fileClient("localhost",1988,"fruit.jpg")
}

class fileClient (host:String, port:Int, file:String){
    var s : Socket ?= null
    var out = ByteArrayOutputStream()
    var msg : MessageBufferPacker = MessagePack.newDefaultBufferPacker()

    init {
        try {
            s = Socket(host,port)
            sendFile(file)
        }catch (e:Exception){
            e.printStackTrace()
        }
    }

    @Throws(IOException::class)
    fun sendFile(file: String) {
        val dos = DataOutputStream(s!!.getOutputStream())
        val buffer = ByteArray(4096)
        val filebytes = File(file).readBytes()
        var msgdata = ByteOutputStream()

        msg.packString(file)
        msg.packBinaryHeader(filebytes.size)
        msg.writePayload(filebytes)

        msg.close()



        val data = msg.toByteArray()
        val datasize = data.size
        val ins = ByteArrayInputStream(data)
        dos.writeInt(datasize)
        while (ins.read(buffer) > 0) {
            dos.write(buffer)
        }
        dos.close()
    }
}

我的服务器代码是

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream
import org.msgpack.core.MessagePack
import org.msgpack.core.MessageUnpacker
import java.awt.List
import java.io.*
import java.net.ServerSocket
import java.net.Socket
import java.text.SimpleDateFormat
import java.util.*

fun main(args: Array<String>) {
    var fs = FileServer(1988)
    fs.start()
}

class FileServer(port: Int) : Thread() {

    private var ss: ServerSocket? = null

    var fileRealName : String ?= null

    init {
        try {
            ss = ServerSocket(port)
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }

    override fun run() {
        while (true) {
            try {
                val clientSock = ss!!.accept()
                saveFile(clientSock)
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
    }

    @Throws(IOException::class)
    private fun saveFile(clientSock: Socket) {
        var msgList = ArrayList<Any>()
        val dis = DataInputStream(clientSock.inputStream)
        val msgdata = ByteOutputStream()
        val buffer = ByteArray(4096)
        var read = 0


        while (true) {
            val datalen = dis.readInt() // data length

            if(datalen!= null && datalen >0){
                var finaldata = ByteArray(datalen)
                var process = 0;
                while (process <= datalen) {
                    read = dis.read(buffer)
                    if (read < 0) {
                        return
                    }
                    msgdata.write(buffer)
                    process += 4096
                }
                println(process.toString() + " "+ datalen.toString())
                var allData = msgdata.toByteArray().slice(0..datalen).toByteArray()
                unpackByte(allData)

            }

        }

        msgdata.close()
        dis.close()
    }

    private fun unpackByte(data:ByteArray){

        var unpacker : MessageUnpacker = MessagePack.newDefaultUnpacker(data)

        var fileName = unpacker.unpackString().toString()

        var filesize = unpacker.unpackBinaryHeader()
        var buffer = ByteArray(filesize)
        unpacker.readPayload(buffer)

        var fos = FileOutputStream(fileName)
        fos.write(buffer)
        fos.close()

        unpacker.close()

    }

}

我要传输的文件是

但是传输后,服务器上的图像是这样的。

如何正确传输此文件?

我没有成功重现你的问题。但是我想我已经找到了可能导致文件传输损坏的错误。

在您的服务器代码中有一个无限循环,returns 立即退出方法,使其余方法无法访问。这是关闭连接和流的清理代码。 OutputStream 很可能没有正确关闭,这就是文件写入损坏的原因。

服务器代码应该是这样的:

val datalen = dis.readInt() // data length

if (datalen > 0) {
    var finaldata = ByteArray(datalen)
     var process = 0;
     while (process <= datalen) {
        read = dis.read(buffer)
        if (read < 0) {
            break
        }
        msgdata.write(buffer)
        process += 4096
    }
    println(process.toString() + " " + datalen.toString())
    val allData = msgdata.toByteArray().slice(0..datalen).toByteArray()
    unpackByte(allData)

}

msgdata.close()
dis.close()

while 循环是不必要的。此外,您可能应该只 break 循环,而不是 return 来自函数。

P.S。 您是否考虑过使用 IOUtils 来处理所有 IO read/writes?使用这个库,你的一半代码可以被替换为几行代码。