Python脚本附加到现有文件,但在8192字节后停止

时间:2015-01-09 07:57:24

标签: python

我遇到了Python程序的问题。这是一个将素数写入文件的简单程序。我写它来练习Python。一切顺利,直到写出几条hunder线。然后写入停止,尽管程序继续运行直到达到最高数字。

我调试了程序,发现为每个素数调用了write_prime函数,但是没有写入文件。我在Linux和Windows7下测试了程序,在两个系统上都出现了同样的问题,尽管在Windows上它写的线路较少。原因在于我认为写入在8192个字符(1个块)之后停止,而Windows使用两个字符作为行尾,因此填充块需要较少的行。

我写了一个类似的程序,但是在那个版本中我只写不读它的文件(我使用一个列表来存储素数并循环遍历列表而不是通过文件)。在那个程序中我没有这个问题,所以我认为它与程序读取和写入同一文件的事实有关。

谁能帮帮我?

这里我展示Linux和Windows中的输出:

在Linux(Ubuntu 14,10)下,编号最高的是8000:

1; 2; 0

2; 3; 1

3; 5; 2

4; 7; 2

...

...

750; 5693; 4

751; 5701; 8

752; 51007; 7993; 30

8192字节的块在位置5之后在第752行结束。 之后我们再看到一个素数: 第1007个素数和数字本身是7993。

在最高编号的windows7下是8000:

文件以相同的数字2,3,5,7等开头,以

结尾

...

...

689; 5171; 4

690; 5179; 8

691; 511007; 7993; 30

因此该文件大约缩短了60行。它是8,206个字节。我认为这是因为windows以“\ r \ n”(2个字符)结束每一行,Linux以“\ n”(1个字符)结束每一行。

因此,在两种情况下,写入在一个块之后结束。

这是完整的程序:

"""  
Calculate prime numbers  

written and tested with python 3.4.2  

- enter the highest number   
- calculate all prime numbers up and until the highest number  

It is possible to run the program more often. It checks out the highest prime  
number in file primenumber.lst and continues from there.  

The file primenumbers.lst consists of lines with 3 fields separated by ';':  
- counter  
- prime number  
- distance to the previous prime number  

"""

from os.path import isfile  

def write_prime(counter, prime, distance):  
    f.write('%d;%d;%d\n' % (counter, prime, distance))  
    return  

"""  
position the file at the last position with seek(0,2) (2 = last position  
in file) and go back with read(1) and seek(position,0) until you found the \n of  
the previous record. Than read the next line (the last line of the file) with  
readline() and split the line into the three fields.  
If the file was not found, then the program runs for the first time.  
In that case you write the prime numbers 2, 3 and 5 to the file.  
You write these three prime number, so we can skip the other numbers that end  
with 5 to save time, for those are not prime numbers.  
"""  

if isfile("primenumber.lst"):  
    f = open("primenumber.lst", "r")  
    f.seek(0,2)  
    position = f.tell() - 2  
    f.seek(position, 0)  

    while f.read(1) != '\n':  
        position -= 1  
        f.seek(position,0)  
    line = str(f.readline()).split(';')  
    print(line)  
    counter = int(line[0])  
    previous = int(line[1])  
else:  
    f = open("primenumber.lst", "w")  
    write_prime(1, 2, 0)  
    write_prime(2, 3, 1)  
    write_prime(3, 5, 2)  
    counter = 3  
    previous = 5  

f.close()  

print('The highest prime number so far is %s' % str(previous))  
startnumber = previous + 1  
highest = int(input("Highest number: "))  

"""  
Walk through all the numbers until the highest number (entered at the screen).  
Skip the numbers that end with 0, 2, 4, 5, 6 or 8, for those are no primes.  

Divide each number by all the prime numbers you found before, until you reach  
the root of the number.  
If the modulo of one division is 0, the number is no prime number and you  
break out of the 'for line in f' loop.  
If it is a prime number write it to the file and break out of the loop.  
"""  

f = open("primenumber.lst", "r+")  

for i in range(startnumber,highest + 1):      # loop to the highest number  
    if str(i)[-1] in ('1', '3', '7', '9'):  
        f.seek(0)  
        root = int(i ** 0.5)  
        for line in f:                       # read all primes in the file  
            line_str = line.split(';')  
            x = int(line_str[1])  

            if i % x == 0:   
                break                   
            if x > (root):   
                counter += 1  
                distance = i - previous  
                previous = i  
                write_prime(counter, i, distance)  
                f.flush()  
                break                 

f.close()

2 个答案:

答案 0 :(得分:0)

你的课程结构非常难以阅读和承担。但我认为问题是你在文件中跳过覆盖旧答案,无法确切地告诉它到底发生了什么(太难以理解),但这似乎是你f.seek(0)的行为。在{@ 1}}循环中找到新的素数 除此之外,当文件已存在时,您的程序出错,您执行的文件搜索不起作用。

使用' a'对您的计划进行重组。文件追加的模式,在开始寻找新的素数之前做一个正确的文件读取以找到素数产生一个好的工作程序,让我找到所有素数并将它们正确地写入文件。虽然它仍然需要更多的工作结构明智的imo。

所以这里

首先,用于检查主文件是否存在的代码以及如果设置了f.flush()counter的值,使用seek和tell命令是不必要的,并且它不起作用。只需读取文件中的所有行,然后检查最后一行是否为最高值,无需对读指针进行任何位置更改。

previous

其次,不是从文件中读回找到的素数,而是每次迭代一次读取素数并存储在变量中

if isfile("primenumber.lst"):  
    f = open("primenumber.lst", "r")
    lines = f.readlines()
    last = [l.split(';') for l in lines][-1]
    counter = int(last[0])
    previous = int(last[1])

然后使用' a'模式开始查找并将新素数写入文件,在我们进行时更新found_prime变量

## Get found primes so far
f = open("primenumber.lst", "r")  
found_primes = []
for line in f:
    line_str = line.split(';')
    found_primes.append(int(line_str[1]))
f.close()

通过这些修改,我发现所有质数高达20000并且它们被正确写入文件

答案 1 :(得分:0)

f = open("primenumber.lst", "r+")  

for i in range(startnumber,highest + 1):      # loop to the highest number  
    if str(i)[-1] in ('1', '3', '7', '9'):  
        f.seek(0)  
        root = int(i ** 0.5)  
        for line in f:                       # read *some* primes in the file  
            line_str = line.split(';')  
            x = int(line_str[1])  

            if i % x == 0:   
                break                   
            if x > (root):                   # shortcut when we reach the root
                counter += 1  
                distance = i - previous  
                previous = i  
                write_prime(counter, i, distance)  # No seek before write!
                f.flush()  
                break

这将从文件的开头开始读取,直到它遇到一个为除数的行(从而证明新数字不是素数)或者大于新数字的近似(浮点)平方根。在后一种情况下,它会立即写入数字。

请注意,这意味着每个数字不会写在最后,而是在某个地方刚刚超过其平方根。一旦这些书面数字中的一个可解析为大数字,这种行为就会再次发生并且位置停止移动;你只是在列表中间写。

另外,我不确定你是否在正确的位置写作;你正在阅读缓冲文本I / O并且在切换到写入之前没有达到目的或寻求。因此,当前f.next()位置可能位于第N行时,实际文件指针可能会向上舍入为read-ahead buffer大小,例如4096.

组合可以解释你的最后一行:691;511007;7993;30实际上是一个部分覆盖的行,这就是它有太多字段的原因。在5179之后我们期望看到5189,但这只是691;51之前的部分;余数1007;7993;30来自更晚的迭代。虽然7993确实是素数,但许多数字已经被覆盖,并且最终这一行将用于假设511007**2下的任何数字也是素数。此时511007可能会被更大的数字覆盖,文件大小会突然增大,但数字检查错误。

open() documentation中隐含的仅附加模式是不可移植的,因此在您编写之前使用SEEK_END进行搜索可能是最佳选择。

作为最后一个缺陷,如果候选数字的平方根高于文件中的最后一个数字,会发生什么? (不可否认,这不应该发生,因为平方根低于先前的素数,每Bertrand's postulate。)