Python:使用时间戳有效地保存字节以进行记录

时间:2015-04-14 07:13:13

标签: python logging save

我有一个UDP包,每隔2秒就会使用socket读取,然后将UDP数据提取到一个bitarray。

bitarray中的每个位对应于特定条件的真/假值。他们对应的条件是静态的。

我想将每个UDP包中的数据存储在硬盘驱动器上,以便稍后阅读这些数据并及时返回以查看每个条件的真/假状态。我一直在考虑使用日志记录模块执行此操作,但它似乎不是非常有效地存储此类数据。我有可以存储的字节,几乎不占用任何空间。我基本上有60个字节和一个时间戳,可以在很长一段时间内存储每2秒。

我希望能够将这些数据存储在一周的文件中。

我应该使用日志记录模块吗?还是有更有效的方法我还没找到。如果有人能指出一个好的图书馆,那就太好了!

此致

贝伦德

1 个答案:

答案 0 :(得分:1)

我还没有找到这样做的图书馆,但您可以使用我为another question撰写的小FileBuffer课程。数据保存在pickled state中,带来的磁盘空间更少,尽管数据不再是人类可读的。但由于您的数据是表示布尔值数组的二进制字符串,因此这可能不是问题:

#!/usr/bin/env python3
# coding: utf-8

import os
import pickle
import time

class BinaryFileBuffer:
    def __init__(self, basename):
        self.basename = basename

    @property
    def fname(self):
    # call other function for better inherit-and-overwrite-behaviour
        return self.get_filename()

    def get_filename(self):
        return '{}.bin'.format(self.basename)

    def write(self, data):
        with open(self.fname, 'ba') as f:
            pickle.dump(data, f)

    def write_ts(self, data):
        self.write((time.time(), data))

    @property
    def size(self):
        return int(os.path.isfile(self.fname) \
                and os.path.getsize(self.fname))

    def __iter__(self):
        if self.size > 0:
            try:
                with open(self.fname, 'br') as f:
                    while True:
                        yield pickle.load(f)
            except EOFError:
                return

    def flush(self):
        if self.size > 0:
            os.remove(self.fname)

此数据表示产生的开销非常小,当使用时间戳保存60字节时,您将在磁盘上获得82字节。假设一周内每两秒60字节,你最终得到23.6MB文件,原始数据为17.3MB。

要让此文件"旋转",只需修改文件名即可包含当前年份和周:

class RotatingBinaryFileBuffer(BinaryFileBuffer):
    def get_filename(self):
        # append year and week number to basename
        return '{}_{}.bin'.format( \
                 self.basename, time.strftime('%Yw%W'))

可能的测试用例如下:

from random import randint
def randstr(strlen):
    # include only printable characters
    return ''.join(chr(randint(32, 126)) for i in range(strlen))
buf = RotatingBinaryFileBuffer('data')
buf.write_ts(randstr(60))
for item in buf:
    print(item)
buflen = max(i for i,_ in enumerate(buf)) + 1
print("\nBytes per entry: {}".format(buf.size/buflen))

这在某种程度上是一个快速的“肮脏的”"自制的解决方案,但也许你有一些用途。