1

I have a Python file that takes the argument -i light1.1 then parses a stats file to see if the current state is 1 or 0. The python file needs to compare the value then either do nothing or change the value and write it back to the same file.

stats file

ligth1=1
light2=0
light3=1

localpub.py file

def main(argv):
  try:
    opts, args = getopt.getopt(argv, "i:h") # Compulsary argument of -i for PHP communication
  except getopt.getoptError:
      print "com.py -i <device.state>"  # Help option print out
      print "or -h for help"
      sys.exit(2)
for opt, arg in opts:
    if opt == "-i":     
        request = arg.split(".")
        with open("stats", "r+") as openFile:   # Temp opens stat file
            for line in openFile:
                if request[0] in line: # Test if requested actuator exist in stats file
                    status = line.rstrip("\n").split("=")   
                    if request[1] == status[1]:
                        print "Same state; Do nothing"
                        break
                    elif int(request[1]) == (1-int(status[1])):
                        print "Diff states! Toggling"
                        newState = status[0] + "=" + request[1] + "\n"
                        print newState
                        openFile.write(newState) # This line deletes the file


if __name__ == "__main__":
    main(sys.argv[1:])      # Runs main function, skips 1st arg as that is the py script name

Any suggestions?

Ari
  • 745
  • 1
  • 7
  • 23
  • open "wr" is not correct. Read http://stackoverflow.com/questions/6648493/open-file-for-both-reading-and-writing – RobertB Oct 21 '15 at 04:40
  • I've added the "r+" mode and changed the variable "file" to "openFile". Using `openFile.seek(0)` I can replace the first line. Is there an associated integer value for the current line scanned? – Ari Oct 21 '15 at 05:44
  • '0' means the first byte of the file. You can see to any position, in bytes. However, I think you are going to have to re-write the whole file, unless you are positive that the number of bytes you are writing exactly overlays the bytes in the file. For example, if the line was 100 bytes long but you are going to replace it with one 80 bytes long, then it would leave 20 bytes of the old line in there. Or if you rewrite it with 120 bytes, then it would overwrite 20 bytes of the next line. If exact, then you need to keep track of how many bytes you read, then seek to there. – RobertB Oct 21 '15 at 21:42
  • In your case the seek position would be the length of the lines you already read (before the rstrip!), up to the character you want to replace. – RobertB Oct 21 '15 at 21:49

2 Answers2

0

This:

with open("stats", "wr") as file:

is definitely wrong. The documentation for streams says to use 'r', 'w', or 'a' with optional suffix '+' and/or suffix 'b' for modes. The string 'wr' is none of these.

Testing with python 2.7 shows that on my system, at least, this open call opens the file for writing, immediately clobbering any existing contents.

(The name file is also not a good idea in general, since it shadows an existing global type-name.)

Once you fix this, you will run into a second problem, which is that to switch between reading a stream and writing it, you must do a seek operation. See, e.g., this question and its answers.

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • The "file" name was incorrectly copied over from an older version, thanks for picking that up. "clobbering any existing contents", this... I'll try working with the "r+" mode. My aim was to find the line, modify it and close the file in one go. – Ari Oct 21 '15 at 05:35
0

The majority of post say it is better to merge a temporary file with the existing file.

First with statement find the matching line to parse for the current state of the requested device.

Second with statement writes the entire file to a temp file.

Finally copyfile replaces the existing file with the modified new file.

with open("stats") as files:
    for lines in files:
        if arg in lines:
            status = lines.rstrip("\n").split("=")
            break
toggledInt = 1-int(status[1])
# ADD NEWLINE BACK INTO FILE    
temp = open("temp", "w")
    with open("stats") as opened:
        for liner in opened:
            if arg in liner:
                temp.write(newLine)
            else:
                temp.write(liner)
temp.close()
shutil.copyfile("temp","stats")
Ari
  • 745
  • 1
  • 7
  • 23