I'm currently making a program that requires a JSON database file. I want the program to check for the file, if it's there then it's perfect, run the rest of the program, but if it doesn't exist create 'Accounts.json' with {} inside the file, instead then run the program.
How would I do this? Whats the most efficient way.
Note: I use this for checking, but how would I create the file:
def startupCheck():
if os.path.isfile(PATH) and os.access(PATH, os.R_OK):
# checks if file exists
print ("File exists and is readable")
else:
print ("Either file is missing or is not readable")
I believe you could simply do:
import io
import json
import os
def startupCheck():
if os.path.isfile(PATH) and os.access(PATH, os.R_OK):
# checks if file exists
print ("File exists and is readable")
else:
print ("Either file is missing or is not readable, creating file...")
with io.open(os.path.join(PATH, 'Accounts.json'), 'w') as db_file:
db_file.write(json.dumps({}))
This is how i did it. I hope it helps.
edit, yeey it looks like a code now :D
import json
import os
def where_json(file_name):
return os.path.exists(file_name)
if where_json('data.json'):
pass
else:
data = {
'user': input('User input: '),
'pass': input('Pass input: ')
}
with open('data.json', 'w') as outfile:
json.dump(data, outfile)
How about wrapping the open file in a try/except? I'm not a professional Python coder, so feel free to weigh in if this is not a kosher approach.
try:
with open('Accounts.json', 'r') as fp:
accounts = json.load(fp)
except IOError:
print('File not found, will create a new one.')
accounts = {}
# do stuff with your data...
with open('Accounts.json', 'w') as fp:
json.dump(accounts, fp, indent=4)
w+ opens with write permissions.
The + creates a new file if one is not found.
filename = 'jsonDB.json'
def openFile():
with open(filename, 'w+') as f:
f.write('{}')
f.close
openFile()
Related
I am trying to create a small game for fun, and I want to save and load previous run scores. I started a test file to mess around and try to figure out how pickling works. I have a pickle file with a small set of number. How do I add numbers to the pickle file and save it for the next run.
Currently I have it like this:
new_score = 9
filename = "scoreTest.pk"
outfile = open(filename,'wb')
infile = open(filename,'rb')
with infile as f:
scores = pickle.load(f)
scores.add(new_score)
pickle.dump(scores, outfile)
When I run it like this I get this error:
EOFError: Ran out of input
If someone could please tell me what is wrong and how to do it correctly that would be great. Apologies for any un-optimal code, I'm new to code.
You are trying to juggle a reader and writer on the same file at the same time. The open(filename, 'wb') of the write deletes whatever happened to be in the file so there is no data for the reader. You should only open the file when you really need to use it. And its better to write to a temporary file and rename it. If something goes wrong you haven't lost your data.
import pickle
import os
new_score = 9
filename = "scoreTest.pk"
tmp_filename = "scoreTest.tmp"
try:
with open(filename, 'rb') as infile:
scores = pickle.load(f)
except (IOError, EOFError) as e:
scores = default # whatever that is
scores.add(new_score)
with open(tmp_filename, 'wb') as outfile:
pickle.dump(scores, outfile)
os.rename(tmp_filename, filename)
I would testing if a file has already been open before writing.
Here my code :
with open(file_five, 'w') as f:
f.write(xml)
I would something as this code example :
if "file_five has already been open"
with open(file_five, 'w') as f:
f.write(xml)
else:
...
There are two ways:
1-> For Excel specific
try:
myfile = open("file_five.csv", "r+") # or "a+", whatever you need
except IOError:
print "Could not open file! !"
with myfile:
do_stuff()
2 -> For any file (Rename approach)
import os
try:
os.rename('file.xls', 'tempfile.xls')
os.rename('tempfile.xls', 'file.xls')
except OSError:
print('File is still open.')
I always open and write into files using with statement:
with open('file_path', 'w') as handle:
print >>handle, my_stuff
However, there is one instance where I need to be able to be more flexible, and write to sys.stdout (or other types of streams), if that is provided instead of file path:
So, my question is this: Is there a way for using with statement both with real files and with sys.stdout?
Note that I can use the following code, but I think this defeats the purpose of using with:
if file_path != None:
outputHandle = open(file_path, 'w')
else:
outputHandle = sys.stdout
with outputHandle as handle:
print >>handle, my_stuff
You can create a context manager and use it like this
import contextlib, sys
#contextlib.contextmanager
def file_writer(file_name = None):
# Create writer object based on file_name
writer = open(file_name, "w") if file_name is not None else sys.stdout
# yield the writer object for the actual use
yield writer
# If it is file, then close the writer object
if file_name != None: writer.close()
with file_writer("Output.txt") as output:
print >>output, "Welcome"
with file_writer() as output:
print >>output, "Welcome"
If you don't pass any input to file_writer it will use sys.stdout.
Thing is, you don't need to use a context processor with stdout, because you're not opening or closing it. A less fancy way of abstracting this is:
def do_stuff(file):
# Your real code goes here. It works both with files or stdout
return file.readline()
def do_to_stdout():
return do_stuff(sys.stdout)
def do_to_file(filename):
with open(filename) as f:
return do_stuff(f)
print do_to_file(filename) if filename else do_to_stdout()
The simplest way is to simply use "old school" streamed filenames, that way your code doesn't have to change. In Unix this is "/dev/tty" or in Windows this is "con" (although there are other choices for both platforms).
if default_filename is None:
default_filename = "/dev/tty"
with open(default_filename, 'w') as handle:
handle.write("%s\n" % my_stuff)
This code tested in Python 2.7.3 and 3.3.5
With python3 optional closefd argument is recognized.
If set to False, resulting IO object won't close underlying fd:
if file_path != None:
outputHandle = open(file_path, 'w')
else:
outputHandle = open(sys.stdout.fileno(), 'w', closefd=False)
with outputHandle as handle:
print(my_stuff, file=handle)
Currently teaching myself Python, and learning file I/O by writing a script to both read from and add text to an existing file. The script runs up until I call the write() method, at which point it throws out a non-specific exception - this is the traceback:
File "test.py", line 13, in <module>
f.write(txt)
IOError: [Errno 0] Error
My code:
from sys import argv
script, filename = argv
f = open(filename, 'a+')
print("The contents of %s are:") % filename
print f.read()
txt = raw_input("What would you like to add? ")
f.write(txt)
print("The new contents are:")
print f.read()
f.close()
My environment is Python 2.7.3 in Win7, PowerShell, and Notepad++.
What is causing this? How would I fix it? In my understanding, the a+ access mode should allow me to both read and append to the file. Changing the access mode to r+ yields the same exception.
Clarifications:
I have an existing text file (a.txt) with a single word in it that I pass as an argument to the script, like so:
python test.py a.txt
I am under an admin account in Windows.
Results:
At the minimum, adding two seek() commands fixes the issue - detailed in the answer post.
A problem when one tries to add a text of little size: it remains in the buffer, that keeps the text before the real writing is done after receiving more data.
So, to be sure to write really, do as it is described in the doc concerning os.fsync() and flush()
By the way, it is better to use the with statement.
And it's still more better to use binary mode. In your case, there shouldn't be a problem because you just add text after the reading and just use seek(o,o) . But when one wants to move correctly the file's pointer into the bytes of the file, it is absolutely necessary to use binary mode [ the 'b' in open(filename, 'rb+') ]
I personnaly never use 'a+', I've never understood what are its effects.
from sys import argv
from os import fsync
script, filename = argv
with open(filename, 'rb+') as f:
print("The contents of %s are:") % filename
print f.read()
f.seek(0,2)
txt = raw_input("What would you like to add? ")
f.write(txt)
f.flush()
fsync(f.fileno())
f.seek(0,0)
print("The new contents are:")
print f.read()
For some reason print f.read() doesn't work for me on OS X when you have opened the file in a+ mode.
On Max OS X, changing the open mode to r+ and then adding a f.seek(0) line before the second read makes it work. Sadly, this doesn't help windows.
This is the working code on Mac OS:
from sys import argv
script, filename = argv
f = open(filename, 'r+')
print("The contents of %s are:") % filename
print f.read()
txt = raw_input("What would you like to add? ")
f.write(txt)
print("The new contents are:")
f.seek(0)
print f.read()
f.close()
This is the only way I could get it to work on windows 7:
from sys import argv
script, filename = argv
f = open(filename, 'r')
print("The contents of %s are:") % filename
print f.read()
f.close()
txt = raw_input("What would you like to add? ")
f = open(filename, 'a')
f.write(txt)
f.close()
f = open(filename, 'r')
print("The new contents are:")
print f.read()
f.close()
Which seems super hacky. This should also work on Mac OS X too.
I have the following code:
import re
#open the xml file for reading:
file = open('path/test.xml','r+')
#convert to string:
data = file.read()
file.write(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>",r"<xyz>ABC</xyz>\1<xyz>\2</xyz>",data))
file.close()
where I'd like to replace the old content that's in the file with the new content. However, when I execute my code, the file "test.xml" is appended, i.e. I have the old content follwed by the new "replaced" content. What can I do in order to delete the old stuff and only keep the new?
You need seek to the beginning of the file before writing and then use file.truncate() if you want to do inplace replace:
import re
myfile = "path/test.xml"
with open(myfile, "r+") as f:
data = f.read()
f.seek(0)
f.write(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>", r"<xyz>ABC</xyz>\1<xyz>\2</xyz>", data))
f.truncate()
The other way is to read the file then open it again with open(myfile, 'w'):
with open(myfile, "r") as f:
data = f.read()
with open(myfile, "w") as f:
f.write(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>", r"<xyz>ABC</xyz>\1<xyz>\2</xyz>", data))
Neither truncate nor open(..., 'w') will change the inode number of the file (I tested twice, once with Ubuntu 12.04 NFS and once with ext4).
By the way, this is not really related to Python. The interpreter calls the corresponding low level API. The method truncate() works the same in the C programming language: See http://man7.org/linux/man-pages/man2/truncate.2.html
file='path/test.xml'
with open(file, 'w') as filetowrite:
filetowrite.write('new content')
Open the file in 'w' mode, you will be able to replace its current text save the file with new contents.
Using truncate(), the solution could be
import re
#open the xml file for reading:
with open('path/test.xml','r+') as f:
#convert to string:
data = f.read()
f.seek(0)
f.write(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>",r"<xyz>ABC</xyz>\1<xyz>\2</xyz>",data))
f.truncate()
import os#must import this library
if os.path.exists('TwitterDB.csv'):
os.remove('TwitterDB.csv') #this deletes the file
else:
print("The file does not exist")#add this to prevent errors
I had a similar problem, and instead of overwriting my existing file using the different 'modes', I just deleted the file before using it again, so that it would be as if I was appending to a new file on each run of my code.
See from How to Replace String in File works in a simple way and is an answer that works with replace
fin = open("data.txt", "rt")
fout = open("out.txt", "wt")
for line in fin:
fout.write(line.replace('pyton', 'python'))
fin.close()
fout.close()
in my case the following code did the trick
with open("output.json", "w+") as outfile: #using w+ mode to create file if it not exists. and overwrite the existing content
json.dump(result_plot, outfile)
Using python3 pathlib library:
import re
from pathlib import Path
import shutil
shutil.copy2("/tmp/test.xml", "/tmp/test.xml.bak") # create backup
filepath = Path("/tmp/test.xml")
content = filepath.read_text()
filepath.write_text(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>",r"<xyz>ABC</xyz>\1<xyz>\2</xyz>", content))
Similar method using different approach to backups:
from pathlib import Path
filepath = Path("/tmp/test.xml")
filepath.rename(filepath.with_suffix('.bak')) # different approach to backups
content = filepath.read_text()
filepath.write_text(re.sub(r"<string>ABC</string>(\s+)<string>(.*)</string>",r"<xyz>ABC</xyz>\1<xyz>\2</xyz>", content))