python - 如何制作较小的临时文件?

标签 python temporary-files

所以我正在编写这个程序来创建曼德尔布罗集的图片,并且我一直在逐步使其变得更好。现在,生成的每个进程都会将一些数据写入临时文件,稍后将使用该文件将图片放在一起。然而,现在临时文件比实际图片本身大得多,我对如何缩小它们没有任何想法。如何有效地将整数数据写入文件并将其取回?我打算最终使其具有很好的可扩展性,因此我需要能够为像素索引编写任意长的整数,但颜色数据始终是三个整数,最大值为 255。这是我的代码:

import multiprocessing

def pixproc(y0, yn, xsteps, ysteps, fname):
    XMIN, YMIN = -2., -1.
    XLEN, YLEN = 3, 2
    with open(fname, 'w') as f:
        for y in xrange(y0, yn):
            print y
            for x in xrange(xsteps):
                c=complex(XMIN + XLEN*(1.*x/xsteps),
                          YMIN + YLEN*(1.*y/ysteps))
                k=c
                for i in xrange(256):
                    k = k*k + c
                    if abs(k)>2: break
                if 0<i<32:
                    #print 'Success!', i
                    print >>f, x, y, 8*i, 0, 0 #This is that part of
                if 32<=i<255:                  #my code that I am trying
                    #print 'Success!', i       #to improve. The rest of 
                    print >>f, x, y, 255, i, i #the code is given for context
    return                                     #and isn't relevant to my question


def main(xsteps, ysteps):
    pool = multiprocessing.Pool()
    n = multiprocessing.cpu_count()
    step = height / n
    fnames = ["temp" + str(i) for i in xrange(n)]
    for i in xrange(n):
        pool.apply_async(pixproc, 
                         (step*i, 
                          step*(i+1), 
                          xsteps, 
                          ysteps, 
                          fnames[i]))
    pool.close()
    pool.join()
    return fnames


if __name__=="__main__":
    from PIL import Image
    import sys
    width, height = map(int, sys.argv[1:])
    picname = "mandelbrot1.png"
    fnames = main(width, height)
    im = Image.new("RGB", (width, height))
    pp = im.load()
    for name in fnames:
        with open(name) as f:
            for line in f:
                line = map(int, line.rstrip('\n').split(' '))
                pp[line[0], line[1]] = line[2], line[3], line[4]
    im.save(picname)

当我尝试制作一张3000x2000的图片时,实际图片是672 KB,但临时文件都接近30 MB!有人可以建议一种更好的方法将数据存储在文件中吗? (重要的部分在pixproc函数中)

最佳答案

假设您只是想消除对临时数据使用基于文本的格式而不是二进制格式的开销,并且您不想重写所有内容以使用 numpy,那么有几种不同的解决方案:

<小时/>

首先,可以先将数据保存为二进制格式:mmap文件,然后使用 ctypes将其视为某种巨大的记录。这通常带来的麻烦大于其值(value),但值得一提。

假设您的数据只不过是一长串 5 字节的元组:

class Entry(ctypes.Structure):
    _fields_ = [("x", ctypes.c_uint8), ("y", ctypes.c_uint8),
                ("i", ctypes.c_uint8), ("j", ctypes.c_uint8), ("k", ctypes.c_uint8)]
Entries = ctypes.POINTER(Entry)
with open(fname, 'wb') as f:
    f.truncate(ctypes.sizeof(Entry * (yn - y0)))
    m = mmap.mmap(f.fileno(), access=mmap.ACCESS_WRITE)
<小时/>

其次,您可以使用struct 。您必须阅读文档才能获得完整的详细信息,但我将举一个例子。让我们看一下这一行:

print >>f, x, y, 8*i, 0, 0

现在,我们假设所有 5 个都保证是字节 (0-255)。你可以这样做:

f.write(struct.pack('BBBBB', x, y, 8*i, 0, 0))

稍后再读:

x, y, i8, 0, 0 = struct.unpack('BBBBB', f.read(struct.calcsize('BBBBB')))
i = i8//8

如果它们中的任何一个需要长于一个字节,则需要处理字节顺序,但这非常简单。例如,如果 xy 范围从 -32768 到 32767:

f.write(struct.pack('>hhBBB', x, y, 8*i, 0, 0))

并确保以二进制模式打开文件。

如果您愿意,您当然可以将其与 mmap 结合使用,这意味着您可以只使用 struct.pack_intostruct.unpack_from > 而不是显式使用 packwriteunpackread

<小时/>

接下来是pickle 。要么直接创建列表,然后 pickle.dump 它,或者手动 pickle.dumps 每个条目并在其上方添加一些简单的高级结构(或者只使用 shelve ,如果该更高级别的结构是或可能是从键到条目的简单映射)。这可能会更大而不是更小,而且可能会更慢,因此在考虑这一点之前您总是希望进行一些测试。但有时这是一个简单的解决方案。

<小时/>

最后,您可能可以想出一种更紧凑的文本格式,而不仅仅是打印每个对象的 str 表示形式。这通常不值得付出努力,但同样值得考虑。

关于python - 如何制作较小的临时文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15911013/

相关文章:

python - Django 编码 - 为什么需要返回两个相同的参数?

python - pandas groupby .sum 如何返回错误的值?

python - 临时货架?

.net - 使用 Path.GetTempFileName 创建的文件会自动清理吗?

python - Pandas 如何根据两列合并两个数据框并更新下一列?

python - Pandas 列中值之间的平均天数差异

python - 如何获取我们的测试用例未命中的文件的代码覆盖率,它仅显示命中的文件

android - 在 Android 中创建临时文件

security - 临时存储敏感数据

c# - 如何使用默认浏览器打开 HTML 文件并在用户查看后将其删除?