1

如何将新的数据列附加到现有的 .txt 文件?基本上我会生成 5 个字典,每次生成一个字典时,我都想将值写入新列中的主文本文件。即使您无法运行它,我也会显示我的代码,因为它调用了我编写的另一个程序:

# Import personal module
import graphGenerator as gg
# Open file for writing data to
case=open(r'J:\FOIL\mediansandmeans.txt','w')
# Run code
for i in range(5):
    # create a graph using NetworkX and a code I wrote to read in an edgelist from a txt file
    G=gg.graph_creator(i+1)
    # calculate degree of all nodes using NetworkX--returns a dictionary
    d=nx.degree(G,weighted=True)
    # print dictionary values to text file
    for j in d.keys():
        case.write('%s\n' % d[j])

现在我如何让程序为每个字典开始一个新列?

4

4 回答 4

5

文本文件按顺序存储;第二行从第一行结束的地方开始。您可以在中间修改材料,但要添加一个字符(或删除一个字符),您需要读取后面的所有内容并将其重新写入文件中的新偏移量。换句话说,您必须像其他人建议的那样,读取和写入整个文件,或者使用不同的存储模型(例如,数据库)。

如果你真的必须按列向文件添加信息,你可以通过写出固定长度的行来完成,用空格填充;然后你在文件中寻找并用新数据覆盖一些空间。我不会提供代码,因为这是一种糟糕的方法:固定长度的记录在 1970 年代就消失了。而且我真的认为在您的情况下没有必要或不合适。

查看您的代码,我认为您不需要将列添加到文件中。我认为最好的解决方案实际上是将值收集在一个二维数组中,这样您就可以在完成后以所需的格式一次将它们全部写出来。除非您有数千兆字节的积分,否则没有理由一次将它们写出一列。

编辑:既然你喜欢数组的想法,这里是如何创建它并轻松写出来:

from collections import defaultdict
degrees = defaultdict(list)

for i in range(5):
    G=gg.graph_creator(i+1)
    d=nx.degree(G,weighted=True)
    for j in d.keys():
       degrees[j].append(d[j])

for k in sorted(degrees.keys()):
    case.write("%s: %s\n" % (k, "\t".join(degrees[k])))

“二维数组”实际上是一个列表字典,与您的版本保持一致。(我认为所有返回的字典都具有完全相同的键。)该代码使用了两个方便的 python 功能:defaultdict该类为您省去了在记录第一列时显式创建每个数组行的麻烦。输出代码将这五个值连接成一个制表符分隔的字符串以供输出。

另请注意,除非您对字典的键进行排序,否则您将以任意顺序获得它们——通常不是您想要的输出。

于 2013-05-23T17:29:18.977 回答
1

正如 Alexis 所解释的,文本文件不是随机访问或修改的。要将新数据插入文本文件的中间,您必须编写一个全新的文件。

但这真的有问题吗?你只这样做了5次。而且,由于现代计算机非常擅长将大量顺序数据发送到硬盘驱动器,而不擅长随机查找和写入,因此浪费的时间可能不会那么多。这很简单。例如:

bakpath = path+'.bak'
os.rename(path, bakpath)
with open(path, 'rb') as infile, open(bakpath, 'wb') as outfile:
    writer = csv.writer(outfile)
    for row, newvalue in zip(csv.reader(infile), newvalues):
        row.append(newvalue)
        writer.writerow(row)

如果是这样,有几种方法可以改进。


最明显的是,您可以使用数据库(如sqlite3)或表系统(如pandaspytables)代替 CSV 文件。除了已经编写好且易于使用之外,它们还可能比您想出的任何东西都得到更好的优化。


或者只是为每一列使用一个单独的文件。您仍然可以访问它们,就像它们是一个文件一样,如下所示:

with closing_all([open(path, 'rb') for path in paths]) as files):
    for row in zip(*files):
        # each row is a tuple of columns

closing_all不是标准库中内置的,但您可以简单地编写它:

@contextmanager
def closing_all(things):
    try:
        yield things
    finally:
        for thing in things:
            thing.close()

如果您需要在最后将它们全部合并到一个文件中,这很容易做到,这意味着您将整个内容重写 1 次而不是 N 次。


您也可以自己构建一个随机访问文件。如果您事先知道最大列长度和列数,您可以用空格填充每一列:

COLUMN_LENGTHS = 20, 15, 41, 12, 19
COLUMN_STARTS = [0] + list(itertools.accumulate(COLUMN_LENGTHS))
ROW_LENGTH = COLUMN_STARTS[-1] + 1

def read_cell(f, row, column):
    f.seek(row * ROW_LENGTH + COLUMN_STARTS[column])
    return f.read(COLUMN_LENGTHS[column]).rstrip()

def write_cell(f, row, column, value):
    f.seek(row * ROW_LENGTH + COLUMN_STARTS[column])
    padded = value.ljust(COLUMN_LENGTHS[column])
    f.write(padded)

如果你事先知道它们,但可以粗略估计,你总是可以使用list和类似类使用的相同技巧:高估,每当你被写出来时,乘以某个常数并将旧的东西复制到一个新扩展的版本。这意味着您只重写文件日志 N 次而不是 N 次。


另一种选择是将文件保持为转置格式,因此您只需添加新行而不是新列。您只需以'a'模式打开文件并写入即可。

如有必要,您始终可以在最后将其转回,这意味着您正在重写文件一次而不是 N 次。

于 2013-05-23T17:58:26.487 回答
0

将新列附加到文本文件将是低效的。要么吞下整个文件,添加你的列,然后覆盖现有文件,要么使用具有原生列概念的东西,如数据库或 xml 文件。

于 2013-05-23T17:23:55.167 回答
0

我同意这将是低效的,但是如果您必须/真的想使用带有列的文件,请制作一个带有' '分隔符的 CSV,如下所示:

例如,如果您为每一行创建一个列表,然后为一列附加您想要的每个值,您可以这样编写它们:

import csv
with open('J:\FOIL\mediansandmeans.csv', 'wb') as case:
    writer = csv.writer(case, delimiter=' ',
                            quotechar='"', quoting=csv.QUOTE_MINIMAL)
    writer.writerow(['your', 'first list', 'of rows'])
    writer.writerow(['your', 'second list', 'of rows'])

您可以在csv 文档中阅读更多内容

但实际上你应该为这类东西使用数据库。你看过sqlite3吗?

于 2013-05-23T17:30:45.070 回答