使用Python逐列写入.txt文件

时间:2013-05-23 17:19:13

标签: python networkx

如何将新数据列附加到现有的.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 个答案:

答案 0 :(得分:5)

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

如果确实必须按列添加信息,可以通过写出固定长度的行填充空格来完成;然后,您搜索文件并用新数据覆盖一些空格。我不会提供代码,因为这是一种可怕的方法:固定长度的记录在20世纪70年代出现了。在你的情况下,我真的不认为这是必要或适当的。

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

编辑:由于您喜欢数组创意,因此以下是创建数据并轻松编写的方法:

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类省去了在记录第一列时显式创建每个数组行的麻烦。并且输出代码将五个值连接到一个以制表符分隔的字符串中以进行输出。

另请注意,除非您对字典的键进行排序,否则您将按照仲裁顺序对其进行排序 - 通常不是您想要的输出。

答案 1 :(得分:1)

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

但这真的是一个问题吗?你只做了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没有内置到stdlib中,但您可以轻松地编写它:

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

如果你需要将它们全部合并到一个文件中,这很容易做到,这意味着你要重写整个事情一次而不是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次。

答案 2 :(得分:0)

将新列附加到文本文件是低效的。要么压入整个文件,添加列,覆盖现有文件,要么使用具有本机概念的列,如数据库或xml文件。

答案 3 :(得分: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 documentation

中阅读更多内容

但实际上你应该使用数据库来处理这类事情。你看过sqlite3吗?