V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
peterpei
V2EX  ›  Java

关于 Java io 的一些问题

  •  
  •   peterpei · 2020-05-08 08:45:17 +08:00 · 2805 次点击
    这是一个创建于 1448 天前的主题,其中的信息可能已经有所发展或是发生改变。

    关于数据处理的一些问题

    最近在做一个小项目,需要在 python 和 Java 之间进行数据传输,用 socket 通信。 python 代码是这样的:

        Head_Info = json.dumps(File_Dire)
        Head_Info_Len = struct.pack('i', len(Head_Info))
        #send file
        Target_Sever.send(Head_Info_Len)
        Target_Sever.send(Head_Info.encode('utf-8'))
        with open(File, 'rb') as F:
            data = F.read()
            Target_Sever.sendall(data)
            print   ("done")
    

    大概就是把数据的长度(4 字节)+数据的一些信息(json)+数据打成一个包。 差不多是这样的:

    B   {"Type": "File", "File_Name": "tempfile.fasttext", "File_Size": 6}hello!
    

    在 python 里面是这样接收数据的:

        Head_Struct = client.recv(1024)
        Head_Len = struct.unpack('i',Head_Struct)[0]
        File_Data_Raw = client.recv(Head_Len)# receve info
    

    但到了 Java,输入变成了 IO 流,我并不能像 python 里面一样分批次拿信息了,只能一下拿完,但是对于文件传输,这相当于破坏了文件的结构,求一个解决思路(尽量在不改动 python 结构的前提下)。

    还有就是关于indexOf函数的一个问题

    我想把上述的数据包中的数据信息提取出来,代码如下

              String ending = "}";
              int info = Fileline.indexOf(ending) - 4;//减去 4 字节的报头
              System.out.println(Fileline.substring(4, info));
    

    输出的结果却是这样的

    {"Type": "File", "File_Name": "tempfile.fasttext", "File_Size
    

    请问是我在哪里出错了吗?
    由于我只是对 coding 感兴趣,并没有进行系统学习,若出错,烦请指正 :)
    Thanks again

    12 条回复    2020-05-13 18:06:01 +08:00
    dallaslu
        1
    dallaslu  
       2020-05-08 08:56:12 +08:00
    和 indexOf 关系不大。重点在于 substring 第二个参数是 endIndex, 不是 length 。

    另外 Java 接收数据是怎么写的呢?
    sandrew1945
        2
    sandrew1945  
       2020-05-08 09:00:28 +08:00   ❤️ 1
    Java 也可以按照长度分批读取流,建议用 netty 来写
    luozic
        3
    luozic  
       2020-05-08 09:11:34 +08:00   ❤️ 1
    使用一种公共的流定义,python 和 java 使用公共的定义通信,保证传输完整性的部分在流定义里面完成。
    n770011
        4
    n770011  
       2020-05-08 09:13:57 +08:00
    InputStream 函数 read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。可以分批次读。至于怎么解析,就看你数据协议怎么设计,如果不好解析那就证明你数据协议设计有问题。
    HivenYang
        5
    HivenYang  
       2020-05-08 09:23:33 +08:00
    拿到字节流,然后先读 4 个字节的长度,根据长度读取相应的字节数,然后进行解析,循环进行此操作,直到数据读完了,简单的么就直接用 io 包下的 ServerSocket,考虑性能么就研究下 NIO 、AIO 和 Netty
    WhenAtRains
        6
    WhenAtRains  
       2020-05-08 09:23:54 +08:00
    python 编码后,java 没有解码正确。我最近学习的 netty 里面 公共的比较简单的解码器有行编解器和固定长度编解码器。但是我觉得比较麻烦的是自己写一个编解码器,尤其是解码。
    zhuangzhuang1988
        7
    zhuangzhuang1988  
       2020-05-08 09:33:05 +08:00 via Android
    最近刚刚在看 mercurial 的 command 传输协议,和你这个像
    https://www.mercurial-scm.org/wiki/CommandServer

    可以看下对应的 java 客服端怎么实现的
    https://bitbucket.org/aragost/javahg/src/default/src/main/java/com/aragost/javahg/internals/HgInputStream.java
    yty2012g
        8
    yty2012g  
       2020-05-08 09:53:03 +08:00
    使用 netty 可以很简单的处理吧,实现一个自定义的 ByteToMessageDecoder,首先标记一下读取位置,然后读取 4byte,得到消息长度,如果 ByteBuf 的剩余长度足够,就直接读取消息长度的内容,否则 return 并等待下一次读取,直到剩余长度满足消息长度。或者如果你不想一次读完,就每次读取就放到一个 byte 数组里面,直到 byte 数组满足待读取的长度。
    wysnylc
        9
    wysnylc  
       2020-05-08 10:18:12 +08:00
    socket.io 少走弯路
    aguesuka
        10
    aguesuka  
       2020-05-08 12:12:19 +08:00 via Android
    java 里的 inputstream 的 read 方法返回的是这次读的 btye 数,比如传入长为 100 的数组,如果返回 40,那么只读到前 40 个,你需要循环 read,直到返回值为-1 或者读到了你想读的字节
    aguesuka
        11
    aguesuka  
       2020-05-08 12:20:16 +08:00 via Android
    比如 python 一次发了两条数据,一条长度为 8 一条为 16 。那第一次用长度为 4 的 byte[]读 4 个字节,第二次用长度为 8byte[]的读 8 个字节,便得到了第一条消息
    xinQing
        12
    xinQing  
       2020-05-13 18:06:01 +08:00
    哈哈,解码错咯。建议用 netty 这样的网络库,自己用 Inputstream 拿自己做宝搞
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3224 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 72ms · UTC 13:56 · PVG 21:56 · LAX 06:56 · JFK 09:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.