Elliot Gorokhovsky
Elliot Gorokhovsky

Reputation: 3762

Python refresh file from disk

I have a python script that calls a system program and reads the output from a file out.txt, acts on that output, and loops. However, it doesn't work, and a close investigation showed that the python script just opens out.txt once and then keeps on reading from that old copy. How can I make the python script reread the file on each iteration? I saw a similar question here on SO but it was about a python script running alongside a program, not calling it, and the solution doesn't work. I tried closing the file before looping back but it didn't do anything.

EDIT: I already tried closing and opening, it didn't work. Here's the code:

import subprocess, os, sys

filename = sys.argv[1]
file = open(filename,'r')
foo = open('foo','w')
foo.write(file.read().rstrip())
foo = open('foo','a')
crap = open(os.devnull,'wb')
numSolutions = 0

while True:
    subprocess.call(["minisat", "foo", "out"], stdout=crap,stderr=crap)
    out = open('out','r')
    if out.readline().rstrip() == "SAT":
        numSolutions += 1
        clause = out.readline().rstrip()
        clause = clause.split(" ")
        print clause
        clause = map(int,clause)
        clause = map(lambda x: -x,clause)
        output = ' '.join(map(lambda x: str(x),clause))
        print output
        foo.write('\n'+output)
        out.close()
    else:
        break

print "There are ", numSolutions, " solutions."

Upvotes: 1

Views: 9227

Answers (3)

25r43q
25r43q

Reputation: 623

You take your file_var and end the loop with file_var.close().

for ... :
    ga_file = open(out.txt, 'r')
    ... do stuff
    ga_file.close()

Demo of an implementation below (as simple as possible, this is all of the Jython code needed)...

__author__ = ''
import time

var = 'false'
while var == 'false':
    out = open('out.txt', 'r')
    content = out.read()
    time.sleep(3)
    print content
    out.close()

generates this output:

2015-01-09, 'stuff added'
2015-01-09, 'stuff added'           # <-- this is when i just saved my update
2015-01-10, 'stuff added again :)'  # <-- my new output from file reads

I strongly recommend reading the error messages. They hold quite a lot of information.

I think the full file name should be written for debug purposes.

Upvotes: 0

Hugh Bothwell
Hugh Bothwell

Reputation: 56674

I rewrote it to hopefully be a bit easier to understand:

import os
from shutil import copyfile
import subprocess
import sys

TEMP_CNF = "tmp.in"
TEMP_SOL = "tmp.out"
NULL = open(os.devnull, "wb")

def all_solutions(cnf_fname):
    """
    Given a file containing a set of constraints,
    generate all possible solutions.
    """
    # make a copy of original input file
    copyfile(cnf_fname, TEMP_CNF)

    while True:
        # run minisat to solve the constraint problem
        subprocess.call(["minisat", TEMP_CNF, TEMP_SOL], stdout=NULL,stderr=NULL)

        # look at the result
        with open(TEMP_SOL) as result:
            line = next(result)
            if line.startswith("SAT"):
                # Success - return solution
                line = next(result)
                solution = [int(i) for i in line.split()]
                yield solution
            else:
                # Failure - no more solutions possible
                break

        # disqualify found solution
        with open(TEMP_CNF, "a") as constraints:
            new_constraint = " ".join(str(-i) for i in sol)
            constraints.write("\n")
            constraints.write(new_constraint)

def main(cnf_fname):
    """
    Given a file containing a set of constraints,
    count the possible solutions.
    """
    count = sum(1 for i in all_solutions(cnf_fname))
    print("There are {} solutions.".format(count))

if __name__=="__main__":
    if len(sys.argv) == 2:
        main(sys.argv[1])
    else:
        print("Usage: {} cnf.in".format(sys.argv[0]))

Upvotes: 1

tdelaney
tdelaney

Reputation: 77367

You need to flush foo so that the external program can see its latest changes. When you write to a file, the data is buffered in the local process and sent to the system in larger blocks. This is done because updating the system file is relatively expensive. In your case, you need to force a flush of the data so that minisat can see it.

    foo.write('\n'+output)
    foo.flush()

Upvotes: 3

Related Questions