C#如何从Stream对象获取字符串 解决蓝牙数据文本显示问题
问题根因
你现在的写法不可能正确展示设备传输的真实内容。numBytesRead是int类型,它存储的仅仅是本次循环从流中读取到的字节总个数,不是流承载的实际业务数据。对它调用ToString()最终只会在界面上输出一个数字——比如本次读了32个字节就显示"32",和对端发来的文本内容没有任何关系。
你代码里真正存了流原始数据的是名为bytes的字节数组,要展示文本,必须把这个字节数组按照和对端约定好的字符编码转成字符串才行。
现有代码的潜在问题
你参考的是本地固定长度文件流的读取写法,直接套在蓝牙通信流上会出问题:
- 蓝牙是流式通信,
input.Length绝大多数场景拿不到准确的待读数据长度,部分实现下甚至会直接抛出“不支持该操作”的异常,上来就根据这个值初始化字节数组,很容易触发崩溃或者读不全数据 - 循环读取时没有处理
Read返回0的场景:如果Read返回0,代表对端已经主动断开了流连接,不做判断的话循环会一直跑下去触发死循环。
修正实现
首先要和蓝牙对端确认传输文本使用的字符编码,通用消费级设备大多用UTF8,老旧嵌入式设备可能用ASCII、GB2312等编码,编码不匹配会出现乱码。
可参考如下修正后的代码:
BluetoothSocket source_device = mysocket.Accept(); output = source_device.OutputStream; input = source_device.InputStream; // 用动态列表缓存读到的字节,不依赖流的Length属性 List<byte> buffer = new List<byte>(); byte[] readTmp = new byte[1024]; // 单次读取缓冲区大小,可根据实际传输数据量调整 while (input.IsDataAvailable()) { int readCount = input.Read(readTmp, 0, readTmp.Length); if (readCount == 0) { // 对端断开连接,跳出循环 break; } // 追加本次读到的有效字节到缓存 buffer.AddRange(readTmp.Take(readCount)); } // 按约定编码转字符串,以下以UTF8为例,可根据实际协议替换 string receivedText = System.Text.Encoding.UTF8.GetString(buffer.ToArray()); // 安卓平台若在子线程执行流读取,必须切回主线程更新UI RunOnUiThread(() => { _data.Text = receivedText; });
补充说明
如果你的场景是设备持续分批次上报数据,不要等IsDataAvailable为false才转码,要提前和对端约定好帧分隔规则(比如固定帧头帧尾、特殊字符分隔、固定长度等),每凑齐一帧完整数据就转码展示,避免出现粘包、半包导致的乱码或者内容缺失。
内容的提问来源于stack exchange,提问作者TechGeek
相关产品推荐
相关产品推荐

