【问题标题】:Save Python dictionary to file, and update it periodically将 Python 字典保存到文件,并定期更新
【发布时间】:2017-11-08 18:38:30
【问题描述】:

我觉得这是一个非常简单的问题,这里有很多非常相似的问题,但我仍然不知道如何得到我想要的。我正在使用在线时可以连接的远程设备。我想要一个记录设备最近正常运行时间的文件,如下所示:

# device ID ......... last seen online
{'deviceID1':'Wed Nov 08 2017 06:11:27 PM',
'deviceID2':'Wed Nov 08 2017 06:11:27 PM',
'deviceID3':'Tues Nov 07 2017 03:47:01 PM'}

等等。通过将其存储在 json 文件中并执行 json.dumps 来存储数据和 json.load 来查看它,我已经非常接近了。我的代码遵循以下步骤:“ping 所有设备 ID”、“检查输出”和“将结果写入文件”。但是每次我这样做时,这些值都会被那些在线但现在不在线的设备覆盖。如在,而不是上面,我得到类似的东西:

# device ID ......... last seen online
{'deviceID1':'Wed Nov 08 2017 06:11:27 PM',
'deviceID2':'Wed Nov 08 2017 06:11:27 PM',
'deviceID3':''}

当我在 2017 年 11 月 8 日星期三下午 6:11:27 检查时,设备 ID3 不在线。但我想在更新我在网上看到的设备的值时保留该值。我怎样才能基本上将这个字典/数据保存在一个文件中,并每次都为同一组唯一的设备 ID 更新它?这个question 是最接近的,但这是关于附加条目的,我想更新已经存在的键的值。谢谢。

相关代码:

def write_to_file(data):
    with open(STATUS_FILE, 'w') as file:
        file.write(json.dumps(data))

def create_device_dictionary(deviceIDs):
    devices = {}
    for i in range(0, len(deviceIDs)):
        devices[deviceIDs[i]] = []
    return devices

def check_ping_output(cmd_output_lines,devices):

    for i, line in enumerate(cmd_output_lines):
        device_id = line.strip().strip(':')
        # if the device pinged back...
        if 'did not return' not in cmd_output_lines[i+1]:
            #current UNIX time
            human_readable_time = time.strftime(
                '%a %b %d %Y %I:%M:%S %p',
                time.gmtime(time.time())
            )
            devices[device_id].append(human_readable_time)
        else:
        #    do something here? I want the device ID to be in the file even if it's never appeared online
             pass

    return devices

【问题讨论】:

  • 说实话我一个字都没读。把一些代码放在那里。如果是为了读书,我会读一本书。
  • 不管设备是否在线,您总是会覆盖 所有 值。在转储 json 之前过滤掉设备列表以仅更新当前在线的设备。到目前为止发布您的代码,我们可以帮助调试它。
  • @mercer721 write_to_file_datacreate_device_dictionary 函数在您的问题中可能不是必需的,但您能否也给我们一个示例 cmd_output_lines
  • @Bahrom,当然。 2 个设备的输出,一个返回,一个不返回,将是:deviceIDa: True deviceIDb: Minion did not return. [No response]
  • 继续这个想法,接下来我会好奇的是在线设备有多个值 - 一个字典,例如,存储设备最近被看到的 5 次在线查看它是否在尝试“ping”或响应每个响应期间下降了一段时间。这将涉及覆盖在线设备的值,而是附加到它们的当前值。所以它看起来像{'device1':'second_most_recent_time',most_recent_time';'device2':'';'device3:'second_most_recent_time',most_recent_time'} 等。想法?

标签: python json file dictionary


【解决方案1】:

这是我想出的一个基本示例(删除您已经解决的 sn-ps 部分,例如时间转换等)

import json

# Suppose this is your existing json file (I'm keeping it as a string for the sake of the example):
devices_str = '{"deviceIDa":"Wed Nov 08 2017 06:11:27 PM", "deviceIDb":"Wed Nov 08 2017 06:11:27 PM", "deviceIDc":"Tues Nov 07 2017 03:47:01 PM"}'

cmd_output_lines = [
    'deviceIDa:True',
    'deviceIDb:Minion did not return. [No response]',
]
# Generate a dictionary of the devices for current update
devices = dict(
    line.strip().split(':') for line in cmd_output_lines
)
# Filter out the ones currently online, using whatever criteria needed
# In my example, I'm just checking if the response contained a True
online_devices = dict(
    (device_id, resp) for (device_id, resp) in devices.iteritems() if 'True' in resp
#               ^ of course in your case that resp would be current/last seen time
)

# Load existing entries
existing_devices = json.loads(devices_str)

# Update them only overwriting online devices
existing_devices.update(online_devices)

# Final result
print json.dumps(existing_devices)

这个输出:

"deviceIDb": "Wed Nov 08 2017 06:11:27 PM", "deviceIDc": "Tues Nov 07 2017 03:47:01 PM", "deviceIDa": "True"}

如您所见,deviceIDa 是唯一更新的条目(deviceIDb 仍然是现有条目中的最后一个)

编辑:

更进一步,如果您想记录最近 5 次在线时间,您可以使用 defaultdict(list),或者使用类似这样的普通字典:

>>> d = {1: [2, 3, 4, 5, 6,]}
>>> new = {1: 7, 2: 4} # only one current online time anyway (no need for list here)
>>> for _id, new_online in new.items():
...     d[_id] = (d.get(_id, []) + [new_online])[-5:] # only take the last 5 elements
...     
>>> d
{1: [3, 4, 5, 6, 7], 2: [4]}
>>> 

【讨论】:

  • 谢谢!最后,我通过添加一个步骤来初始化具有所有设备 ID 的字典并且如果 json 文件尚不存在则没有时间戳,我这样做略有不同。但是你对拥有一个不同的“online_devices”字典并用它来更新主字典的想法帮助很大——我需要这个关键步骤
  • @mercer721 不用担心,很高兴这有帮助!
  • 酷。 update() 不会扩展到这种情况是有道理的。我觉得这样做太复杂了——保存一个带有列表作为值的字典,并随着时间的推移更新特定的键——但我想我的情况有点具体。感谢这些建议!
【解决方案2】:

建议您按照以下步骤操作,而不是将创建的数据直接写入文件:

  1. 读取上次查看的文件,并将其转换为字典。
  2. 检查字典中的每个设备ID,并更新字典中的值 如果设备在线。
  3. 检查所有不在最后一次看到的字典中的设备,并将它们的时间戳添加到字典中。
  4. 用当前修改的字典运行 json.dumps 的结果替换文件的内容。

【讨论】:

  • 谢谢!这个流程帮助我完成了它,但@Bahrom 的回答更深入。此外,我需要采取措施确保所有设备最终都在字典中,即使它们从未在线。
【解决方案3】:

基本上,JSON 不是你想要的。 一方面 - 您不能只将新值附加到 JSON 数据文件,因为它需要关闭结构。

接下来,尽管您可以多次重复使用某个键来构建 JSON 数据,但当将其转换为纯 Python dict 时,无论如何只有最后一个值是可见的(或者,如果您调整了解析器,则会出现异常)。

所以,只是一个普通文件,其中每条记录都是一个新行,想想“CSV” - 对你来说会更好。或者,您可以选择一次将所有内容移动到 SQL DB,例如 sqlite。

【讨论】:

  • 我认为提问者可以使用 JSON,因为密钥没有被重用。我们只关心最近的正常运行时间,这始终是每台设备的单一值。
  • 感谢@jsbueno,但我不希望每次查找设备是否在线时都换行。它们都有唯一的 ID,我想将其保留为每台设备的一个键值对
猜你喜欢
  • 2016-03-29
  • 1970-01-01
  • 1970-01-01
  • 2017-07-14
  • 2021-03-23
  • 1970-01-01
  • 2022-12-15
  • 1970-01-01
  • 2017-03-16
相关资源
最近更新 更多