如何在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 + "\""); } }
效率优化建议
目前用逗号分隔整数的方式传输二进制数据效率极低,且容易出错。建议直接传输二进制数据:
- 客户端上传时,不要把
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); }
- 服务器端先接收元信息文本帧,再接收二进制数据;客户端接收时,设置WebSocket的
binaryType: 'arraybuffer',直接处理二进制帧,省去字符串拆分和转换的步骤。
内容的提问来源于stack exchange,提问作者Svyatoslav Kuralenok
相关产品推荐
相关产品推荐

