避免在Python中将“\n”写入文件的最后一行。

7

我正在将多行内容写入新文件(可能达到几GB),代码如下:

for item in record:
    output_pass.write('%s\n' %item)

然而,由于最后一条记录的 '\n',我得到了一条空白的记录,例如:

文件开始

record111111

reocrd222222

record333333

---a blank line---

文件结束

由于我的文件很大,我不想再次读取文件。那么,有没有一种简单的方法来防止这种情况发生,或者轻松删除文件中的最后一个 '\n'?

我的解决方案:

感谢所有的帮助!

我认为我不会将整个文件加载到内存中,因为它可能非常巨大。

我实际上是通过先写入第一条记录,然后在循环中写入其余行来解决这个问题的。我将 '\n' 放在前面,这样它就不会出现在最后一行。

但是乔纳森是对的。我实际上并没有 '\n' 在最后一行的问题,主要是我的强迫症。

这是我的代码:

rec_first = parser_fastq.next() #This is just an iterator of my file
output.write('%s' %('>'+rec_first[0].strip('@')))
output.write('\n%s' %(rec_first[1])) #I put '\n' in the front

count = 1

#Write the rest of lines
for rec_fastq in parser_fastq:
    output.write('\n%s' %('>'+rec_fastq[0].strip('@')))
    output.write('\n%s' %(rec_fastq[1]))
    count += 1
    print 'Extracting %ith record in %s ...' %(count, fastq_name) + '\b'*100,

output.close()

打印'\n%i个记录被写入%s' %(计数,fasta_name)


2
你确定这真的是个问题吗?实际上,大多数基于文本的工具(例如大多数Unix工具)都期望在文件末尾有一个换行符(即换行符旨在作为行终止符,而不是分隔符)。 - Matteo Italia
你真的想在输出文件中每个项目之间都有那么多空白行吗?看起来好像每个项目都以两个 '\n' 字符结尾。 - martineau
1
文件之所以巨大,是因为单个“记录”中有太多的数据,还是因为您正在处理许多记录,这些记录总共可能达到如此之大的大小?对此的答案可能会影响到真正最适合您需求的答案。 - martineau
8个回答

14

这应该是一个简单的解决方案:

for item in record[:-1]:
    output_pass.write("%s\n" % item)
output_pass.write("%s" % record[-1])

如果您说文件很大,join 并不推荐使用 - 它将在内存中创建整个文件内容字符串。


upv 用于教育为什么不推荐使用 join - Bhargav Rao
2
对于列表来说,切片表达式[:]会创建该列表的一个副本,因此你也浪费了内存。 - myaut
@Bhargav:目前从问题中并不清楚是否需要避免使用join,因为我们并不知道record中可能有多少项,也不知道每个项的字符串表示可能有多大。就像这里的许多问题一样,问题的参数不明确。 - martineau
@martineau 先生,因此使用 join 也不是错误的吗? - Bhargav Rao
1
@Bhargav:我的观点是它可能会正常工作,但如果没有来自OP的其他信息,我们就无法知道它是否会正常工作。 - martineau
这对于 io.readio.write 不起作用:TypeError: '_io.TextIOWrapper' 对象没有属性 'getitem'。 - loretoparisi

2
这需要不断的额外内存:
for i, item in enumerate(record):
    if i>0: 
        output_pass.write('\n')
    output_pass.write('%s' %item)

1

你尝试使用计数器吗?例如:

record = [str(x) for x in range(10)]
print record

import sys
output_pass=sys.stdout

counter = 0

while counter != (len(record))-1:
   output_pass.write("%s\n" % record[counter])
   counter += 1

这个应该怎么运作?即使假设 record 是一个列表(从代码中看它可能不是,只是看起来像可枚举对象),你的代码只是倒序打印它,跳过最后一个元素,总是留下换行符。http://ideone.com/UvNCsJ - Matteo Italia
这将以相反的顺序打印文件内容。因此,您需要编写另一个代码来执行另一个方向的解析;) - Bhargav Rao
@MatteoItalia 是的,抱歉...我不知道当时在想什么;拿你的代码然后“重新排列”。 - yhoyo
@BhargavRao 现在代码没有最后一行也能正常工作 :P http://ideone.com/h8mfa5 - yhoyo

1
下面的代码将快速输出 record 中除最后一个记录外的所有记录,并在每个记录之间添加换行符,然后再输出最后一条记录,但不添加换行符。这样做不需要太多额外的内存。
(对于 Python 3,请使用 range 而不是 xrange)
item = iter(record)
for _ in xrange(len(record)-1):
    output_pass.write('%s\n' % next(item))

output_pass.write('%s' % next(item))

感谢您的帮助,先生。我恢复了我的答案,希望一些迷路的程序员能够找到它有用。再次感谢。 - Bhargav Rao

1
你可以先加入它们,然后像这样编写
item = '\n'.join(record)
output_pass.write('%s' %item)

注意

如果您的列表,即record不包含字符串,则需按照Martinaeu所提到的方式将其映射到一个str,即'\n'.join(map(str, record)),然后再写入文件。(在py2中)


1
OP在谈论一个多GB的文件,这种情况下这绝对是个坏主意(它会先在内存中创建整个字符串)。 - Matteo Italia
@MatteoItalia 谢谢。如果完全错误,请告诉我,以便我可以删除它。 - Bhargav Rao
本质上并没有错,但在这种情况下,它将成为性能噩梦(不仅会在内存中创建整个字符串,而且无用的 '%s' % item 还会再次创建它的副本)。 - Matteo Italia
Bhargav和@Matteo:这可能行不通,不是因为“record”可能很大(尽管它可能很大,这可能是一个问题),而是因为它很可能不是字符串序列(但我们不能确定),这就是“join()”方法要求其第一个参数的内容 - 因此,按照原样编写,最有可能的结果是“TypeError: sequence item 0: expected string, xxx found”。如果“record”不是禁止使用的(并且将其每个项目转换为字符串也不是禁止使用的),则可以轻松解决这个问题,即使用“map(str,record)”。 - martineau
@martineau先生,非常感谢您。我已经编辑了答案并包含了您的想法。再次感谢。 - Bhargav Rao
显示剩余4条评论

0

或者您可以定义一个函数来将文件写入。

def writeFile(value): 
    open('file.txt', 'a') as file 
    file.write(value)
    file.write('\n')

然后您调用此定义来将数据写入文件。 "value" 将在一行中。

writeFile('HelloWorld') 

0

应该可以工作。 对于列表中的最后一项使用.replace("\n", "")。

for item in items:
    print item[0], line[1].replace("\n", "")

0

我认为你不应该担心一个尾随的 \n。在许多情况下它是有益的(比如如果你想添加另一行),甚至作为 flake8 Python 源代码分析器的一部分,它也被推荐使用。

@Amir 的答案可以避免写入换行符。

如果你想删除最后一行,你可以直接按原样写入整个文件,然后创建一个文件对象来使用 seek() + read() 来测试最后一个字符,然后 seek()truncate() 来删除它——在 seek 之后调用 read 将需要第二个 seek

这在这个 Q&A 中得到了广泛的解释:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接