Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何有效地删除大文件的第一行?_Python_Python 3.x_Logging_File Io - Fatal编程技术网

Python 如何有效地删除大文件的第一行?

Python 如何有效地删除大文件的第一行?,python,python-3.x,logging,file-io,Python,Python 3.x,Logging,File Io,这个问题已经被问过了,但是没有一个解决方案对我有效 在Python 3中,如何有效地从大文件中删除第一行? 我正在编写一个需要日志记录的程序,日志文件有一个可配置的最大大小,可以是无限的。因此,我不想使用readlines()或类似的方法,因为这些方法会占用大量内存。速度不是一个大问题,但是如果不重写整个文件,也不需要临时文件就可以做到,那就太好了 解决方案需要跨平台 示例日志文件: [09:14:56 07/04/17] [INFO] foo [23:45:01 07/04/17] [WARN

这个问题已经被问过了,但是没有一个解决方案对我有效

在Python 3中,如何有效地从大文件中删除第一行?

我正在编写一个需要日志记录的程序,日志文件有一个可配置的最大大小,可以是无限的。因此,我不想使用
readlines()
或类似的方法,因为这些方法会占用大量内存。速度不是一个大问题,但是如果不重写整个文件,也不需要临时文件就可以做到,那就太好了

解决方案需要跨平台

示例日志文件:

[09:14:56 07/04/17] [INFO] foo
[23:45:01 07/04/17] [WARN] bar
[13:45:28 08/04/17] [INFO] foobar
... many thousands more lines
输出:

[23:45:01 07/04/17] [WARN] bar
[13:45:28 08/04/17] [INFO] foobar
... many thousands more lines
此代码将在循环中运行:

while os.path.getsize(LOGFILE) > MAXLOGSIZE:
    # remove first line of file
以下解决方案均不起作用且内存效率低:

解决方案#1-有效但效率低下

with open('file.txt', 'r') as fin:
    data = fin.read().splitlines(True)
with open('file.txt', 'w') as fout:
    fout.writelines(data[1:])
解决方案#2-不起作用,将文件留空

import shutil

source_file = open('file.txt', 'r')
source_file.readline()
target_file = open('file.txt', 'w')

shutil.copyfileobj(source_file, target_file)
解决方案#3-有效,但使用额外的文件:

with open("file.txt",'r') as f:
    with open("new_file.txt",'w') as f1:
        f.next() # skip header line
        for line in f:
            f1.write(line)

试试这个。它使用你提到的第三种方法,但不会生成新文件

filePath = r"E:\try.txt"
file_str = ""
with open(filePath,'r') as f:
        f.next()  # skip header line
        for line in f:
            file_str = file_str + line

with open(filePath, "w") as f:
    f.write(file_str)

因此,这种方法非常粗糙。如果您的线条尺寸大致相同,且标准偏差较小,则效果良好。我们的想法是将文件的一部分读入一个缓冲区,该缓冲区足够小,可以节省内存,但足够大,这样两端的书写形式就不会把事情弄糟(因为行的大小大致相同,差异很小,我们可以交叉手指祈祷它能工作)。我们基本上会跟踪我们在文件中的位置并来回跳转。我使用
collections.deque
作为缓冲区,因为它从两端都具有良好的
append
性能,并且我们可以利用队列的FIFO特性:

from collections import deque
def efficient_dropfirst(f, dropfirst=1, buffersize=3):
    f.seek(0)
    buffer = deque()
    tail_pos = 0
    # these next two loops assume the file has many thousands of
    # lines so we can safely drop and buffer the first few...
    for _ in range(dropfirst):
        f.readline()
    for _ in range(buffersize):
        buffer.append(f.readline())
    line = f.readline()
    while line:
        buffer.append(line)
        head_pos = f.tell()
        f.seek(tail_pos)
        tail_pos += f.write(buffer.popleft())
        f.seek(head_pos)
        line = f.readline()
    f.seek(tail_pos)
    # finally, clear out the buffer:
    while buffer:
        f.write(buffer.popleft())
    f.truncate()
现在,让我们用一个运行良好的假装文件来尝试这一点:

>>> s = """1. the quick
... 2. brown fox
... 3. jumped over
... 4. the lazy
... 5. black dog.
... 6. Old McDonald's
... 7. Had a farm
... 8. Eeyi Eeeyi Oh
... 9. And on this farm they had a
... 10. duck
... 11. eeeieeeiOH
... """
最后:

>>> import io
>>> with io.StringIO(s) as f: # we mock a file
...     efficient_dropfirst(f)
...     final = f.getvalue()
...
>>> print(final)
2. brown fox
3. jumped over
4. the lazy
5. black dog.
6. Old McDonald's
7. Had a farm
8. Eeyi Eeeyi Oh
9. And on this farm they had a
10. duck
11. eeeieeeiOH

如果
dropfirst
<
buffersize
有一点“松弛”,那么这应该算是正常的。因为您只想删除第一行,所以只需保留
dropfirst=1
,您可以将
buffersize=100
设置为安全。它将比阅读“成千上万行”更节省内存,如果没有一行比前几行大,那么您应该是安全的。但请注意,这是一个非常粗糙的边缘。

这不是一个有效的内存解决方案。此外,我还收到以下错误:
AttributeError:“\u io.TextIOWrapper”对象没有属性“next”
。这是因为它是第三方解决方案,需要其他模块吗?@retnikt否,这是因为在python 3中,您需要使用
next(f)
而不是
f。next()
这不是大文件的解决方案。您的脚本将失败,因为所有内存都将被使用。经过大量测试,这似乎在100%的时间内都能正常工作。从代码上看,您所说的应该是正确的-它的行为应该不可靠。但出乎意料的可靠性对我来说很好@retnikt如果您强制执行一个行长度(在未到达末尾的地方填充,当它结束时生成一个新行),那么您可以获得可靠的行为。这可能比它的价值更麻烦,所以,在一个不起作用的例子中,假设有一条很长的线,大约len>200,并且有100行以前只有一个字符(即新行),那么它将失败,而且不漂亮。这就是你的意思。我误解了你。很抱歉