-1

I have this code

 with codecs.open("file.json", mode='a+', encoding='utf-8') as f:

I want:

1) Create file if it does not exists, and start writing from the start of file.

2) If exists, first read it and truncate it and then write something.

I found this somewhere

 ``r''   Open text file for reading.  The stream is positioned at the
         beginning of the file.

 ``r+''  Open for reading and writing.  The stream is positioned at the
         beginning of the file.

 ``w''   Truncate file to zero length or create text file for writing.
         The stream is positioned at the beginning of the file.

 ``w+''  Open for reading and writing.  The file is created if it does not
         exist, otherwise it is truncated.  The stream is positioned at
         the beginning of the file.

 ``a''   Open for writing.  The file is created if it does not exist.  The
         stream is positioned at the end of the file.  Subsequent writes
         to the file will always end up at the then current end of file,
         irrespective of any intervening fseek(3) or similar.

 ``a+''  Open for reading and writing.  The file is created if it does not
         exist.  The stream is positioned at the end of the file.  Subse-
         quent writes to the file will always end up at the then current
         end of file, irrespective of any intervening fseek(3) or similar.

a+ mode suits me best but what it does that it only lets me write at end of file,

With a+ mode I have this f.seek(0) immediately after opening file, but it has no affect, it does not seek to the start of file.

Umair Ayub
  • 19,358
  • 14
  • 72
  • 146

4 Answers4

1

Let's say you have a file a with content:

first line
second line
third line 

If you need to write from the start of the file, just do:

with open('a','r+') as f:
    f.write("forth line")

Output:

forth line
second line
third line

If you need to remove the current content and write from the start, do:

with open('a','r+') as f:
    f.write("forth line")
    f.truncate()

Output:

forth line

If you need to append after the existing file, do:

with open('a','a') as f:
    f.write("forth line")

Output:

first line
second line
third line
forth line

And, as you suspected, you will not be able to seek to 0 in a+ mode. You might see details from here

Edit:

Yes, you can dump json with this configuration and still indent. Demo:

dic = {'a':1,"b":2}

import json
with open('a','r+') as f:
    json.dump(dic,f, indent=2)

Output:

{
  "a": 1, 
  "b": 2
}third line
Community
  • 1
  • 1
Ahsanul Haque
  • 10,676
  • 4
  • 41
  • 57
0

You can check if the file exists, and then branch accordingly like so:

import os.path
file_exists = os.path.isfile(filename) 

if file_exists:
    # do something
else:
    # do something else

Hope this helps!

  • There is no other way? I mean I though I maybe misusing file modes – Umair Ayub Nov 16 '16 at 14:43
  • 2
    Downvoting this, because OP asks if he could solve the problem with file modes, and there is nothing about it in the answer. – Ahsanul Haque Nov 16 '16 at 15:05
  • In multiprocessing or multithreading situations, there is a race condition. – RemcoGerlich Nov 16 '16 at 15:11
  • The original question doesn't specifically ask if the problem can be solved with file modes. He mentioned it "suits him best", I was just offering an alternative solution. Fair enough regarding the race condition though. –  Nov 16 '16 at 15:13
0

Use os.path.isfile():

import os

if os.path.isfile(filename):
    # do stuff
else:
    # do other stuff

As to your second question about writing to the begging of a file, then don't use a+. See here for how to prepend to a file. I'll post the relevant bits here:

# credit goes to @eyquem. Not my code

def line_prepender(filename, line):
    with open(filename, 'r+') as f:
        content = f.read()
        f.seek(0, 0)
        f.write(line.rstrip('\r\n') + '\n' + content)
Community
  • 1
  • 1
Christian Dean
  • 22,138
  • 7
  • 54
  • 87
0

You can open the file using os.open to be able to seek and have more control, but you won't be able to use codecs.open or a context manager then, so it's a bit more manual labor:

import os
f = os.fdopen(os.open(filename, os.O_RDWR | os.O_CREAT), 'r+')
try:
    content = f.read()
    f.seek(0)
    f.truncate()
    f.write("Your new data")
finally:
    f.close()
RemcoGerlich
  • 30,470
  • 6
  • 61
  • 79