【问题标题】:nput stream read does not convert all data输入流读取不会转换所有数据
【发布时间】:2020-07-03 15:26:11
【问题描述】:

我正在为必须通过蓝牙与其他设备通信的 Android 设备编写应用程序。 (另一个设备只是一个板子,比如带有蓝牙的 Raspery pi)

这个其他设备接受命令列表,我是单字节,如“A”、“X”、“C”等,当您发送命令时,它总是返回一些响应,如“OK”、“ERROR4”或其他数据,例如“0000000000000001230120000000”。

我已经在我的应用程序中实现了大部分命令并且它们运行良好。但是我对最后一个返回 1748 字节的命令有疑问。大多数时候我都在使用这种方法来获得响应,并且效果很好:

private String send(byte [] bytes) {
        if(bluetoothService == null)
            return null;

        if(bluetoothSocket == null)
            return null;

        String line = "";

        Log.wtf("BYTESARR", Arrays.toString(bytes));

        try {
            OutputStream outputStream = bluetoothSocket.getOutputStream();
            InputStream inputStream = bluetoothSocket.getInputStream();

            outputStream.write(bytes);
            outputStream.flush();

            BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
            line = r.readLine();

        } catch (IOException e) {
            e.printStackTrace();
        }

        return line;
    }

但是对于响应为 1748 字节的命令,方法高于冻结我的应用程序。所以我只为那个命令实现了第二种方法,你在下面看到。

OutputStream outputStream = bluetoothSocket.getOutputStream();
            InputStream inputStream = bluetoothSocket.getInputStream();

            outputStream.write(bytes);
            outputStream.flush();

            char [] b = new char[1540];
            BufferedReader r = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            int from = 0;

            for(int i = 0; i < EXCEPTIONS_NUMBER; i++){
                int asdf = r.read(b, from, 50); // from and len are related to B not R
                Log.wtf("READ", asdf + " <");
                from += asdf;
            }

            line = new String(b);

Log.wtf("LINE", line);

但该方法的问题是我的响应如下所示:(

...0000000000000������������...

这个响应的不到一半是 0(零),这是我所期望的,但是这个响应的第二部分是那些奇怪的问号(我认为应该是零),我不知道为什么会这样?

问题 1)为什么当我读取 1748 字节的响应时,第一种方法让我的应用程序冻结? 问题 2) 为什么第二种方法给我的是奇怪的问号而不是零?

编辑 [已解决] 我找到了解决方案。所以基本上我必须像这样使用ByteArrayInputStream

byte [] b = new byte[1538];
ByteArrayInputStream bais = new ByteArrayInputStream(b);
inputStream.read(b);

这允许我从b 数组中读取所有bytes,并允许我在需要时使用bais。我不确定为什么这个解决方案有效。但我很高兴它奏效了。如果有人理解它并且可以解释会很棒。如果没有,我会更新帖子,当找出它为什么工作时,如果帖子不会被关闭/删除。

【问题讨论】:

  • .readLine() 尝试读取一行。您可以发送 1768 个字节,然后让最后一个字节成为换行符 '\n'。
  • 是的,我明白这一点,但对我来说很奇怪它适用于其他命令。每个命令的响应格式都是相同的,至少我在文档中读过。

标签: java android inputstream


【解决方案1】:
  1. 当您调用r.readLine() 时,该方法将在满足以下两个条件之一之前返回:流返回一个行分隔符,或者流表示它没有更多数据。如果这两种情况都没有发生,您的应用将无限期“冻结”。

  2. 当您使用new char[1540] 创建一个字符数组时,它会填充“NUL”字符 - ASCII/Unicode 代码 0 的非打印控制字符(不要与 Java 中的“null”对象引用混淆)。当您从流中读取时,您将数组的一些内容替换为您读取的字符,但一些原始 NUL 保留在原处,这些将成为您稍后创建的字符串。

要修复,请使用您已写入的数组部分创建字符串:

line = new String(b, 0, from);

【讨论】:

  • 谢谢,这有点帮助,我的意思是现在我可以从设备中读取更多字节,但第二部分仍然是那个奇怪的“菱形问号”标志。不确定这是否意味着设备会向我发送 Null(或类似的东西),但我告诉过它应该是零。
  • 答案的最后一行涵盖了这一点。它将根据您实际从设备收到的chars 创建字符串,这不是b 数组中的所有chars。
  • 在实施您的解决方案之前,我正在读取 780 个零,当我使用您的解决方案时,这是一个问题,我可以读取大约 900 个零,但该字符串中仍然出现 800 个“奇怪的问号”。我添加到我的“for”循环line = new String(b, 0, from); 但这只是有点帮助没有解决我的问题 100%
  • 设备是只返回数字 0-9 还是返回文本或二进制数据? “�”也是当二进制输入无法使用您正在使用的字符编码转换为文本时使用的标准替换字符
  • 是的,它也返回字母,导致我收到的响应是 ...... 0x0D - 起始字节,0x0F - 结束字节,command_byte - 通常是字母,X,Y,T 等取决于命令,RES_BYTE 它是一个数字,因为我只使用日期和时间。 RES_BYTE 只是数字,不包含冒号或斜杠。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多