You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中将有符号整数转换为字符?(PNG传输场景)

问题:Socket传输C++二进制文件到JS时的字符转换问题

我尝试通过Socket将C服务器中的PNG文件以整数形式(范围-128至127,对应C标准字符)传输到JavaScript端,但使用String.fromCharCode()方法无法正常工作——该方法对负数的转换结果与C++中的字符转换不一致,请问JavaScript中还有其他可用的方法吗?

客户端(JS)接收代码

socket.onmessage = function (event) {
                const splitted = event.data.split("|")
                if (splitted[0] === "file -d") {
                    let data = splitted[2].split(",")
                    data = String.fromCharCode(...data)
                    console.log(data)
                    const link = document.createElement("a")
                    const file = new Blob([data], { type: 'application/octet-stream;charset=utf-8' })
                    link.href = URL.createObjectURL(file)
                    link.download = splitted[1]
                    link.click()
                    URL.revokeObjectURL(link.href)
                } else
                    console.log("Received from the server: \"" + event.data + "\"")
            }

服务器端(C++)发送代码

connection->send("file -d|" + "my.png" + "|" + "-119,80,78,71,13,...); // just binary data but char-->int

客户端(JS)上传代码

submitFile.onmousedown = function () {
        if (connected === true) {
            let file = fileStorage.files[0]
            let fileBuffer = new ArrayBuffer(0)
            let fileReader = new FileReader()
            fileReader.onloadend = function (event) {
                fileBuffer = event.target.result
                let fileData = new Int8Array(fileBuffer)
                socket.send("file -u|" + file.name + "|" + "./files|" + file.size + "|" + fileData)
            }
            fileReader.readAsArrayBuffer(file)
        } else
            alert("No connection to the server")
    }

解决方案

核心问题原因

String.fromCharCode()是用于生成UTF-16字符的方法,它会把传入的整数当作UTF-16码点处理。而你的C++端是把signed char(-128~127)转成整数传输,负数对应的二进制位会被fromCharCode解析成无效的UTF-16字符,直接破坏了PNG的二进制结构。

正确处理方式

直接将收到的整数数组转换成字节数组(Uint8Array),再包装成Blob即可还原原始二进制文件:

socket.onmessage = function (event) {
    const splitted = event.data.split("|")
    if (splitted[0] === "file -d") {
        // 将逗号分隔的字符串转成整数数组
        const intArray = splitted[2].split(",").map(num => parseInt(num, 10));
        // 转成Uint8Array:自动将负数映射为对应的无符号字节(和C++中signed char转unsigned char结果一致)
        const byteArray = new Uint8Array(intArray);
        // 直接用字节数组创建Blob,不需要转字符串
        const file = new Blob([byteArray], { type: 'application/octet-stream' });
        
        const link = document.createElement("a");
        link.href = URL.createObjectURL(file);
        link.download = splitted[1];
        link.click();
        URL.revokeObjectURL(link.href);
    } else {
        console.log("Received from the server: \"" + event.data + "\"");
    }
}

效率优化建议

目前用逗号分隔整数的方式传输二进制数据效率极低,且容易出错。建议直接传输二进制数据:

  1. 客户端上传时,不要把Int8Array转成字符串,直接发送ArrayBuffer:
fileReader.onloadend = function (event) {
    fileBuffer = event.target.result;
    // 先发送文本帧告知文件元信息
    socket.send(JSON.stringify({
        type: "file-u",
        name: file.name,
        path: "./files",
        size: file.size
    }));
    // 再发送二进制帧
    socket.send(fileBuffer);
}
  1. 服务器端先接收元信息文本帧,再接收二进制数据;客户端接收时,设置WebSocket的binaryType: 'arraybuffer',直接处理二进制帧,省去字符串拆分和转换的步骤。

内容的提问来源于stack exchange,提问作者Svyatoslav Kuralenok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 04:01:25