1

我正在测试协议缓冲区并尝试读取 csv 文件,对其进行序列化并将输出写入二进制文件,然后使用 ParseFromString 读取二进制文件。我能够序列化和写入二进制文件,但是在读取它时会给出索引越界异常,或者在另一种情况下它只输出二进制文件的最后一行,它会跳过它之前的所有内容。

我的消息很简单,它有两个字段,时间和指标使用。

syntax="proto3";

message excelData {

string time=1;
string meterusage=2;
}

序列化和写入二进制文件代码如下:

import metric_pb2 
import sys
from csv import reader
 

excel_data=metric_pb2.excelData()

with open('out.bin', 'wb') as f:
    with open('data.csv', 'r') as read_obj:
        csv_reader = reader(read_obj)
        header = next(csv_reader)
        if header != None:
            for row in csv_reader:
                excel_data.time=row[0]
                excel_data.meterusage=row[1]
                f.write(excel_data.SerializeToString())

f.close()
read_obj.close()

麻烦的部分如下:

方法 1:这只返回二进制文件的最后一行。它会跳过之前的所有内容。

答案集中只有一行,而不是整个二进制文件

excel_data=metric_pb2.excelData()

with open('out.bin', 'rb') as f:
    content=f.read()
    excel_data.ParseFromString(content)
    print(excel_data.time)
    print(excel_data.meterusage)

方法 2:如果我读取像上面的 csv 文件这样的序列化二进制文件,它会给我一个索引超出范围的错误。我的倾向是二进制文件可能是字节数据并且不包含给出此错误的字符串数据类型?

使用 message.ParseFromString() 读取这个二进制文件的正确方法是什么,因为通过循环读取它不起作用,也不能整体读取它?我创建的二进制文件的快照如下:

二进制输出

4

1 回答 1

1

你成功了吗?

这是为您提供的一个 hacky 解决方案,它(根据 Protobuf流式传输多个消息的技术)将(可变!)消息长度作为每个记录之前的字节写入。

作家

import metric_pb2
import sys

from csv import reader

excel_data = metric_pb2.excelData()

with open('out.bin', 'wb') as f:
    with open('data.csv', 'r') as read_obj:
        csv_reader = reader(read_obj)
        header = next(csv_reader)
        if header != None:
            for row in csv_reader:
                excel_data.time = row[0]
                excel_data.meterusage = row[1]
                bytes = excel_data.SerializeToString()
                # Write the message's integer length as bytes
                f.write(len(bytes).to_bytes(1, sys.byteorder))
                # Write the message itself as bytes
                f.write(bytes)

f.close()
read_obj.close()

产生:

00000000: 1c 0a13 3230 3231 2d30 312d 3031 2030 303a 3030 3a30 3012 0535 342e 3635  ...2021-01-01 00:00:00..54.65
00000010: 1c 0a13 3230 3231 2d30 312d 3031 2030 303a 3030 3a30 3012 0535 352e 3138  ...2021-01-01 00:00:00..55.18
00000030: 1b 0a13 3230 3231 2d30 312d 3031 2030 303a 3030 3a30 3012 0435 352e 38    ...2021-01-01 00:00:00..55.8

注意 1c== 28(因为54.6555.18)和1b== 27(因为55.8

读者

import metric_pb2
import sys

excel_data = metric_pb2.excelData()

with open('out.bin', 'rb') as f:
    while True:
        # Read the message's length as bytes and convert it to an integer
        len = int.from_bytes(f.read(1), sys.byteorder)
        # Read that number of bytes as the message bytes
        bytes = f.read(len)
        if not bytes:
            break

        excel_data.ParseFromString(bytes)
        print("[{time}] {meterusage}".format(
            time=excel_data.time,
            meterusage=excel_data.meterusage))

产生:

[2021-01-01 00:00:00] 54.65
[2021-01-01 00:00:00] 55.18
[2021-01-01 00:00:00] 55.8
[2021-01-01 00:00:00] 56.0
[2021-01-01 00:00:00] 63.52
[2021-01-01 00:00:00] 78.1
于 2021-05-18T16:28:20.353 回答