android-app开发数据传输问题

本人开发android app 通过wifi与硬件设备进行连接,类似物联网项目。通讯协议使用的是与硬件共同制定的。硬件设备使用C语言,android 我这边使用的是java。(没有服务器,也不想用服务器!)

目前遇到的问题:

  1. 嵌入式设备(C语言)通过wifi按16进制字节传输JPG数据,Android(Java语言)获取inputStream将数据读到byte[],将byte[]数据写入文件,目前android图片显示异常,想要正常Android正确显示图片。(图片采用JPG格式)图片效果如下:

img

部分代码如下:


while (true) {
    if (wCmdId == enNetCmd.CMD_PostDownloadFileData) {

        PictureData = new byte[wSize - 89];
        len = inputStream.read(PictureData);

        try {
            FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/ftp" + FileName, true);
            fos.write(PictureData, 0, len);
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.如果实现的方式不对,请问使用什么方式去传输图片数据?请详细地说明解决问题的方法以及实现的方式。

你的可能没有读全,对结果len判断一下,没读全继续读

你打印一下那个len的大小,看看是否和图片大小一样,如果一样考虑写入文件问题,不一样考虑网络传输问题

你尝试下面2个方法,试试吧,如果有帮助,解决的话请采纳

方法一

//初始化streams
final FileOutputStream fileOutputStream = new FileOutputStream(toWriteTo + url.getPath().replaceAll(".*/", ""));
final InputStream inputStream = socket.getInputStream();
 
// Header end flag
boolean headerEnded = false;
 
byte[] bytes = new byte[2048];
int length;
while ((length = inputStream.read(bytes)) != -1) {
    // 如果已经到达标头的末尾,则照常将字节写入文件。
    if (headerEnded)
        fileOutputStream.write(bytes, 0, length);
     
    // 通过比较当前字节和接下来的 3 个字节来定位标头的末尾,
    // HTTP 标头结尾为“\r\n\r\n”(整数表示形式为 13 10 13 10),
    // 如果到达头部末尾,则将标志设置为 true,
    // 并将当前缓冲的字节数组中的剩余数据写入文件。
    else {
        for (int i = 0; i < 2048; i++) {
            if (bytes[i] == 13 && bytes[i + 1] == 10 && bytes[i + 2] == 13 && bytes[i + 3] == 10) {
                headerEnded = true;
                fileOutputStream.write(bytes, i+4, 2048-i-4);
                break;
            }
        }
    }
}
inputStream.close();
fileOutputStream.close();

方法二
你可以参考Netty附带的实现,您可以按如下方式实现它:ChunkedInput<ByteBuf>

public class ChunkedList implements ChunkedInput<ByteBuf> {
    private static final byte[] EMPTY = new byte[0];
    private byte[] previousPart = EMPTY;
    private final int chunkSize;
    private final Iterator<Object> iterator;

    public ChunkedList(int chunkSize, List<Object> objs) {
        this.chunkSize = chunkSize;
        this.iterator = objs.iterator();
    }


    public ByteBuf readChunk(ChannelHandlerContext ctx) {
        return readChunk(ctx.alloc());
    }

    public ByteBuf readChunk(ByteBufAllocator allocator) {
        if (isEndOfInput())
            return null;
        else {
            ByteBuf buf = allocator.buffer(chunkSize);
            boolean release = true;
            try {
                int bytesRead = 0;
                if (previousPart.length > 0) {
                    if (previousPart.length > chunkSize) {
                        throw new IllegalStateException();
                    }
                    bytesRead += previousPart.length;
                    buf.writeBytes(previousPart);
                }
                boolean done = false;
                while (!done) {
                    if (!iterator.hasNext()) {
                        done = true;
                        previousPart = EMPTY;
                    } else {
                        Object o = iterator.next();
                        byte[] bytes = o instanceof String ? ((String) o).getBytes() : (byte[]) o;
                        bytesRead += bytes.length;
                        if (bytesRead > chunkSize) {
                            done = true;
                            previousPart = bytes;
                        } else {
                            buf.writeBytes(bytes);
                        }
                    }
                }
                release = false;
            } finally {
                if (release)
                    buf.release();
            }
            return buf;
        }
    }

    public long length() {
        return -1;
    }

    public boolean isEndOfInput() {
        return !iterator.hasNext() && previousPart.length == 0;
    }

    public long progress() {
        return 0;
    }

    public void close(){
        //close
    }
}

你的这一行代码不是获取全部的流数据,len = inputStream.read(PictureData);,并且也没有对输入流关流的操作。

  1. 首先图片显示不全,或者花屏,是图片bitmap缺失后加载出现。
  2. 传输时校验一下数据大小
  3. 使用while循环完全读取数据
  4. 保存数据后判断大小验证是否传输完成。

    byte[] bytes = new byte[2048];
        int len = -1;
        Log.d(Constants.TAG, " writeToFile 3");
        while ((len = inputStream.read(bytes)) != -1) {
//            Log.d(Constants.TAG, Arrays.toString(bytes));
            randomFile.write(bytes, 0, len);
        }

通过 socket 通讯读取 inputStream 到 byte[] 数组不会改变图片数据本身。inputStream 和 byte[] 都是用来存储数据的容器,从 inputStream 读取数据到 byte[] 数组只是在两个容器之间进行数据的复制。这并不会改变图片数据本身。

但是,在进行数据读取和复制的过程中,如果出现了异常或者数据丢失,可能会导致图片显示异常。因此,在进行数据读取和复制的过程中,应该注意检查异常并确保数据的完整性。

例如,在读取数据时,可以使用 try-catch 语句来捕获异常,并进行相应的处理;在复制数据时,可以使用一些校验和算法来确保数据的完整性。

如果图片显示异常,可能是因为在处理图片数据时出现了问题,例如图片格式不正确、图片数据损坏或丢失等。可以尝试检查代码,确保在处理图片数据时的正确性。

通过测试,一般情况下接收2048字节,但是有的时候会接收1359字节,判断一下长度,将不够的继续inputStream.read(),然后将数据拼接。