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

Python脚本附加到现有文件,但在8192字节后停止,python,Python,我对Python程序有问题。这是一个将素数写入文件的简单程序。我写它是为了练习Python。在写下几百行之前,一切都很顺利。然后,尽管程序继续运行,但写入仍会停止,直到达到最大值 我调试了这个程序,发现write_prime函数是为每个素数调用的,但它不会写入文件。我在Linux和Windows7下测试了这个程序,在这两个系统上都出现了相同的问题,尽管在Windows上写的行数更少。在我看来,这样做的原因似乎是8192个字符(1个块)之后,写入停止,Windows使用两个字符作为行尾,因此填充一

我对Python程序有问题。这是一个将素数写入文件的简单程序。我写它是为了练习Python。在写下几百行之前,一切都很顺利。然后,尽管程序继续运行,但写入仍会停止,直到达到最大值

我调试了这个程序,发现write_prime函数是为每个素数调用的,但它不会写入文件。我在Linux和Windows7下测试了这个程序,在这两个系统上都出现了相同的问题,尽管在Windows上写的行数更少。在我看来,这样做的原因似乎是8192个字符(1个块)之后,写入停止,Windows使用两个字符作为行尾,因此填充一个块所需的行数更少

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

谁能帮我

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

在Linux(Ubuntu14,10)下,最大数量为8000:

一,;2.0

二,;3.一,

三,;5.二,

四,;7.二,

750;5693;四,

751人;5701;八,

752人;51007;7993;三十

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

windows7下的最大数字为8000:

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

689;5171;四,

690;5179;八,

691人;511007;7993;三十

因此,该文件大约缩短了60行。它是8206字节。我认为这是因为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()

你的程序的结构让人难以阅读和理解。但我认为问题在于,你在文件中跳转,覆盖了旧的答案,不能确切地说出它发生在哪里(很难理解),但这似乎是你的
f.seek(0)
以及
f.flush()
在寻找新素数的循环中的行为 除此之外,当文件已经存在时,您的程序出现故障,您所做的文件搜索不起作用

使用文件附加的“A”模式对程序进行重构,在开始查找新素数之前进行正确的文件读取以找到素数,这为我找到所有素数并将它们正确写入文件提供了一个很好的工作程序。尽管在结构方面,它仍然需要更多的工作

现在开始

首先,用于检查主文件是否存在以及如果存在,则设置
计数器
previous
的值的代码对于seek和tell命令来说是不必要的,并且不起作用。只需读取文件中的所有行,然后检查最后一行的最大值,无需更改读取指针的任何位置

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])
其次,不是从文件中读回找到的素数,而是每次迭代读取一次素数并存储在变量中

## 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()
然后使用“a”模式开始查找并向文件写入新的素数,并在执行过程中更新找到的\u prime变量

f = open("primenumber.lst", "a")
for i in range(startnumber,highest + 1):
    if str(i)[-1] in ('1', '3', '7', '9'):
        root = int(i ** 0.5)
        for prime in found_primes:
            if i % prime == 0:
                break;
            if prime > (root):
                counter += 1
                distance = i - previous
                previous = i
                write_prime(counter, i, distance)
                found_primes.append(i)
                break
f.close()
通过这些修改,我发现所有的素数都高达20000,并且它们都被正确地写入了文件中

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行,但实际的文件指针可能会向上舍入到某个大小,例如4096

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

即使在中仅附加模式也意味着不可移植,因此在编写之前使用
seek\u END
进行seek可能是一种方法


最后一个缺陷是,如果候选编号的平方根高于文件中的最后一个编号,会发生什么情况?(无可否认,这不应该发生,因为平方根低于先前的素数。)

在Windows上,除非以二进制模式(“rb”)打开文件,否则\r\n文件是隐藏的。这也意味着当执行seek或tell时,每行的偏移量可以是一个字节。如果我正确地阅读了您的描述,您似乎正在四处寻找,将文本附加到一个文件中:带有open(“primenumber.lst”,“a”)作为f:f.write(“下一行”\n)。谢谢Yann,seek(2)就是解决方案。关于你对候选人号码平方根的评论,请