如何更新 pickle 文件?

How to update pickle files?

所以我将一堆功能保存为 .pkl 文件。这是我最初用来保存文件的代码。

with open('variables.pkl', 'wb') as output:
    pickle.dump(embedding_weights, output, 2)
    pickle.dump(X1, output, 2)
    pickle.dump(X2, output, 2)
    pickle.dump(Y, output, 2)
    pickle.dump(X1_test, output, 2)
    pickle.dump(X2_test, output, 2)
    pickle.dump(Y_test, output, 2)
    pickle.dump(X1_nli, output, 2)
    pickle.dump(X2_nli, output, 2)
    pickle.dump(Y_nli, output, 2)
    pickle.dump(X1_test_nli, output, 2)
    pickle.dump(X2_test_nli, output, 2)
    pickle.dump(Y_test_nli, output, 2)
    pickle.dump(X1_test_matched, output, 2)
    pickle.dump(X2_test_matched, output, 2)
    pickle.dump(Y_test_matched, output, 2)
    pickle.dump(X1_test_mismatched, output, 2)
    pickle.dump(X2_test_mismatched, output, 2)
    pickle.dump(Y_test_mismatched, output, 2)
    pickle.dump(X2_two_sentences, output, 2)
    pickle.dump(X2_test_two_sentences, output, 2)
    pickle.dump(tokenizer, output, 2)

注意:我按原样收到了这些数据,这是用于生成它的代码。我无法重新运行上面的代码,因为这些是需要数小时计算的深度学习功能。因此我将无法对文件进行任何更改 variables.pkl 文件大小约为 1.93GB。在此之后,我想使用以下代码更新 X1_test 文件和 X2_test 文件:

with open('variables.pkl', 'wb') as output:
     pickle.dump(X1_test, output, 2)
     pickle.dump(X2_test, output, 2)

我的理解是它只会更新这两个文件。相反,它删除了所有文件,只剩下这两个文件。文件大小现在只有 12.6KB。想知道我做错了什么吗?我怎样才能在保持其他所有内容不变的情况下只更新上述两个文件。

而不是将所有变量一个接一个地直接转储到文件中;构造一个字典,其中的键表示变量名称和值作为实际数据。

最初节省:

with open('variables.pkl', 'wb') as output:
    d = {'X1': X1, 'X2': X2}
    pickle.dumps(d, output)

正在更新这些值:

#Open existing
with open('variables.pkl', 'rb') as file:
    d = pickle.load(file)

#Update the values
d['X1'] = X1
d['X2'] = X2

#Save
with open('variables.pkl', 'wb') as file:
    pickle.dumps(d, file)

pickle 是一个可以写入文件的字节序列。 您可以将多个 pickle 一个接一个地写入同一个文件,但通常您不能删除和替换文件中间的第一个 pickle 或任何其他 pickle。

1.) 您以 "wb" 模式打开文件,这会截断文件。因此所有数据都丢失了。 但想象一下你会以不同的方式打开模式 "r+" 例如

第一个 pickle 需要例如 300 字节 因此,第二个泡菜从偏移量 300 开始。

现在假设您以 read/write 模式打开文件,并在文件偏移量 0 处写入一个新的 pickle。但是不幸的是,现在您的 pickle 需要 301 个字节。 您会覆盖第二个腌制对象的第一个字节。 第二个 pickle 将因此变得不可读,如果第三个 pickle 对象的开头,找到位置甚至会非常棘手。

您可以改为: 要么执行完整的读取/修改写入。

意思是将所有 pickle 读回临时变量,修改你想要更改的那个,然后写回所有内容。

另一种选择是使用 shelve 模块 ( https://docs.python.org/3.6/library/shelve.html ),它的行为类似于泡菜字典。

您的代码可能如下所示:

import shelve

d = shelve.open("mydata.shlv")

d['embedding_weights'] = embedding_weights
d['X1'] = X1
d['X2'] = X2
d['Y'] = Y
d['X1_test'] = X1_test
d['X2_test'] = X2_test
d['Y_test'] = Y_test
d['X1_nli'] = X1_nli
d['X2_nli'] = X2_nli
d['Y_nli'] = Y_nli
d['X1_test_nli'] = X1_test_nli
d['X2_test_nli'] = X2_test_nli
d['Y_test_nli'] = Y_test_nli
d['X1_test_matched'] = X1_test_matched
d['X2_test_matched'] = X2_test_matched
d['Y_test_matched'] = Y_test_matched
d['X1_test_mismatched'] = X1_test_mismatched
d['X2_test_mismatched'] = X2_test_mismatched
d['Y_test_mismatched'] = Y_test_mismatched
d['X2_two_sentences'] = X2_two_sentences
d['X2_test_two_sentences'] = X2_test_two_sentences
d['tokenizer'] = tokenizer
d.close()

但是,如果您必须坚持当前的文件格式并且您有足够的可用磁盘 space,您可以执行以下操作:

with open('variables.pkl', 'rb') as input:
  with open("newvariables.pkl", "wb") as output:
    pickle.dump(pickle.load(input), output, 2) # embedding_weights
    pickle.dump(pickle.load(input), output, 2) # X1 
    pickle.dump(pickle.load(input), output, 2) # X2
    pickle.dump(pickle.load(input), output, 2) # Y
    pickle.load(input) # read and discard X1_test
    pickle.dump(new_X1_test, output, 2)
    pickle.load(input) # read and discard X2_test
    pickle.dump(new_X2_test, output, 2)
    pickle.dump(pickle.load(input), output, 2) # Y_test ...
    pickle.dump(pickle.load(input), output, 2) # X1_nli
    ...
# now you could rename variables.pkl to oldvariables.pkl
# and rename newvariables.pkl to variables.pkl

pickle 文件格式是顺序格式。因此,如果您更改一项,至少必须重写文件中该位置后面的所有内容。 wb 打开一个仅以二进制格式写入的文件。如果文件存在,它会覆盖文件。如果文件不存在,则创建一个新文件进行写入。

因为文件是二进制格式,我看不到更新文件的方法,但仍然可以追加 - 检查 ab 格式。

要解决您的问题,正确的方法是先在读取模式下解压文件,将文件内容加载到 Python 变量中,对变量执行更新,然后打开wb 中的文件以覆盖它。下面给出的是执行以下操作的代码。

with open('variables.pkl', 'rb') as file:
    variable_dict = pickle.load(file)

variable_dict['X1_test'] = X1
variable_dict['X2_test'] = X2

with open('variables.pkl', 'wb') as file:
    pickle.dumps(variable_dict, file)