Errno 22 invalid mode w+ or filename - python

IOError: [Errno 22] invalid mode ('w+') or filename: 'hodor_2017-05-09_14:03:38.txt'
So I was having issues creating a file where as it is "name" [delimiter] "datetime" .txt
I was looking up different bits of code such as:
Turn a string into a valid filename?
python: how to convert a string to utf-8
https://github.com/django/django/blob/master/django/utils/safestring.py
and it still seems to not work for me.
My concept is simple: given a name and content write a file with that name and that content.
My code is:
def create_json_file(name, contents):
filename = u"%s_%s.json" % (name, datetime.datetime.now().strftime("%Y/%m/%d_%H:%M:%S"))
print "%s" % filename
filename = slugify(filename)
f = open(filename, "w+")
f.write(contents)
f.close()
and as you can see i have been tweaking it. I was looking up the results that django does, which uses slugify.
My original did not have that line. Maybe there is a better way to name the file too. I think the name and datetime is pretty normal but i wasnt sure what delimiters I should be using between name and datetime etc.
For the record, I am not currently using Django because i dont have a need for the framework. I am just trying to test a way to pass in a string and a json map and turn it into a config.json file essentially.
Eventually, I will want to leverage an AJAX request from a website to do this, but that is outside the scope of this question.

Use a different separator in your filename mask:
filename = u"%s_%s.json" % (name, datetime.datetime.now().strftime("%Y_%m_%d_%H%M%S"))
The OS is trying to open 2005/04/01_5:45:04.json. Slashes aren't allowed in file/directory names.
Edit: Removed colons in response to comments.

Related

Edit Minecraft .dat File in Python

I'm looking to edit a Minecraft Windows 10 level.dat file in python. I've tried using the package nbt and pyanvil but get the error OSError: Not a gzipped file. If I print open("level.dat", "rb").read() I get a lot of nonsensical data. It seems like it needs to be decoded somehow, but I don't know what decoding it needs. How can I open (and ideally edit) one of these files?
To read data just do :
from nbt import nbt
nbtfile = nbt.NBTFile("level.dat", 'rb')
print(nbtfile) # Here you should get a TAG_Compound('Data')
print(nbtfile["Data"].tag_info()) # Data came from the line above
for tag in nbtfile["Data"].tags: # This loop will show us each entry
print(tag.tag_info())
As for editing :
# Writing data (changing the difficulty value
nbtfile["Data"]["Difficulty"].value = 2
print(nbtfile["Data"]["Difficulty"].tag_info())
nbtfile.write_file("level.dat")
EDIT:
It looks like Mojang doesn't use the same formatting for Java and bedrock, as bedrock's level.dat file is stored in little endian format and uses non-compressed UTF-8.
As an alternative, Amulet-Nbt is supposed to be a Python library written in Cython for reading and editing NBT files (supposedly works with Bedrock too).
Nbtlib also seems to work, as long as you set byteorder="little when loading the file.
Let me know if u need more help...
You'll have to give the path either relative to the current working directory
path/to/file.dat
Or you can use the absolute path to the file
C:user/dir/path/to/file.dat
Read the data,replace the values and then write it
# Read in the file
with open('file.dat', 'r') as file :
filedata = file.read()
# Replace the target string
filedata = filedata.replace('yuor replacement or edit')
# Write the file out again
with open('file.dat', 'w') as file:
file.write(filedata)

How to extract the full path from a file while using the "with" statement?

I'm trying, just for fun, to understand if I can extract the full path of my file while using the with statement (python 3.8)
I have this simple code:
with open('tmp.txt', 'r') as file:
print(os.path.basename(file))
But I keep getting an error that it's not a suitable type format.
I've been trying also with the relpath, abspath, and so on.
It says that the input should be a string, but even after casting it into string, I'm getting something that I can't manipulate.
Perhaps there isn't an actual way to extract that full path name, but I think there is. I just can't find it, yet.
You could try:
import os
with open("tmp.txt", "r") as file_handle:
print(os.path.abspath(file_handle.name))
The functions in os.path accept strings or path-like objects. You are attempting to pass in a file instead. There are lots of reasons the types aren't interchangable.
Since you opened the file for text reading, file is an instance of io.TextIOWrapper. This class is just an interface that provides text encoding and decoding for some underlying data. It is not associated with a path in general: the underlying stream can be a file on disk, but also a pipe, a network socket, or an in-memory buffer (like io.StringIO). None of the latter are associated with a path or filename in the way that you are thinking, even though you would interface with them as through normal file objects.
If your file-like is an instance of io.FileIO, it will have a name attribute to keep track of this information for you. Other sources of data will not. Since the example in your question uses FileIO, you can do
with open('tmp.txt', 'r') as file:
print(os.path.abspath(file.name))
The full file path is given by os.path.abspath.
That being said, since file objects don't generally care about file names, it is probably better for you to keep track of that info yourself, in case one day you decide to use something else as input. Python 3.8+ allows you to do this without changing your line count using the walrus operator:
with open((filename := 'tmp.txt'), 'r') as file:
print(os.path.abspath(filename))

Read all the text files in a folder and change a character in a string if it presents

I have a folder with csv formated documents with a .arw extension. Files are named as 1.arw, 2.arw, 3.arw ... etc.
I would like to write a code that reads all the files, checks and replaces the forwardslash / with a dash -. And finally creates new files with the replaced character.
The code I wrote as follows:
for i in range(1,6):
my_file=open("/path/"+str(i)+".arw", "r+")
str=my_file.read()
if "/" not in str:
print("There is no forwardslash")
else:
str_new = str.replace("/","-")
print(str_new)
f = open("/path/new"+str(i)+".arw", "w")
f.write(str_new)
my_file.close()
But I get an error saying:
'str' object is not callable.
How can I make it work for all the files in a folder? Apparently my for loop does not work.
The actual error is that you are replacing the built-in str with your own variable with the same name, then try to use the built-in str() after that.
Simply renaming the variable fixes the immediate problem, but you really want to refactor the code to avoid reading the entire file into memory.
import logging
import os
for i in range(1,6):
seen_slash = False
input_filename = "/path/"+str(i)+".arw"
output_filename = "/path/new"+str(i)+".arw"
with open(input_filename, "r+") as input, open(output_filename, "w") as output:
for line in input:
if not seen_slash and "/" in line:
seen_slash = True
line_new = line.replace("/","-")
print(line_new.rstrip('\n')) # don't duplicate newline
output.write(line_new)
if not seen_slash:
logging.warn("{0}: No slash found".format(input_filename))
os.unlink(output_filename)
Using logging instead of print for error messages helps because you keep standard output (the print output) separate from the diagnostics (the logging output). Notice also how the diagnostic message includes the name of the file we found the problem in.
Going back and deleting the output filename when you have examined the entire input file and not found any slashes is a mild wart, but should typically be more efficient.
This is how I would do it:
for i in range(1,6):
with open((str(i)+'.arw'), 'r') as f:
data = f.readlines()
for element in data:
element.replace('/', '-')
f.close()
with open((str(i)+'.arw'), 'w') as f:
for element in data:
f.write(element)
f.close()
this is assuming from your post that you know that you have 6 files
if you don't know how many files you have you can use the OS module to find the files in the directory.

Cannot open filename that has umlaute in python 2.7 & django 1.9

I am trying doing a thing that goes through every file in a directory, but it crashes every time it meets a file that has an umlaute in the name. Like รค.txt
the shortened code:
import codecs
import os
for filename in os.listdir(WATCH_DIRECTORY):
with codecs.open(filename, 'rb', 'utf-8') as rawdata:
data = rawdata.readline()
# ...
And then I get this:
IOError: [Errno 2] No such file or directory: '\xc3\xa4.txt'
I've tried to encode/decode the filename variable with .encode('utf-8'), .decode('utf-8') and both combined. This usually leads to "ascii cannot decode blah blah"
I also tried unicode(filename) with and without encode/decode.
Soooo, kinda stuck here :)
You are opening a relative directory, you need to make them absolute.
This has nothing really to do with encodings; both Unicode strings and byte strings will work, especially when soured from os.listdir().
However, os.listdir() produces just the base filename, not a path, so add that back in:
for filename in os.listdir(WATCH_DIRECTORY):
fullpath = os.path.join(WATCH_DIRECTORY, filename)
with codecs.open(fullpath, 'rb', 'utf-8') as rawdata:
By the way, I recommend you use the io.open() function rather than codecs.open(). The io module is the new Python 3 I/O framework, and is a lot more robust than the older codecs module.

Using variables in creating a file name

I'm pretty new to python, and am wondering if there's any way to put a variable into a file name, so that you can create files with different names each time.
In my particular case, I'd like to add date and time to the file name. If it was possible, this would work perfectly:
example = open("Path/to/file%s", "w") % str(datetime.now())
...but it doesn't. Is there any way to get that sort of functionality using a different approach? I've tried searching for an answer either way using multiple phrasings, but I can't find a yea or nay on it.
Thanks in advance guys.
EDIT: That was supposed to be an open() function, adjusted accordingly.
This should work. format() will replace the placeholder {0} in the string with the formatted datetime string (datestr).
>>> from datetime import datetime
>>> datestr = datetime.strftime(datetime.today(), "%Hh %Mm %Ss %A, %B %Y")
>>> examplefile = open("/home/michael/file{0}".format(datestr), 'w')
>>> print(examplefile)
<open file '/home/michael/file21h 20m 34s Monday, September 2012', mode 'w' at 0x89fcf98>
Modifying your answer to still use the old-style % formatting, you might do:
example = open("Path/to/file%s" % datetime.now(), "w")
Note that I've called open(), which is probably what you want to do (otherwise you're just creating a tuple). Also, using the %s format specifier automatically converts the argument to a string, so you don't really need the str().
The reason your example doesn't work has nothing to do with files.
example = ("Path/to/file%s", "w") % str(datetime.now())
The above is using the % operator with a tuple on the left, and a string on the right. But the % operator is for building strings based on a string template, which appears on the left of the %. Putting a tuple on the left just doesn't make sense.
You need to break what you want to do into more basic steps. You start with "I want to open a file whose name includes the current date and time". There is no way to directly do that, which is why you couldn't find anything about it. But a filename is just a string, so you can use string operations to build a string, and then open that string. So your problem isn't really "how do I open a file with the date/time in the name?", but rather "how do I put the date/time into a string along with some other information?". You appear to already know an answer to that question: use % formatting.
This makes sense; otherwise we'd have to implement every possible string operation for files as well as for strings. And also for everything else we use strings for. That's not the way (sane) programming works; we want to be able to reuse operations that already exist, not start from scratch every time.
So what you do is use string operations (that have nothing to do with files, and neither know nor care that you're going to eventually use this string to open a file) to build your filename. Then you pass that string to the file opening function open (along with the "w" string to specify that you want it writeable).
For example:
filename = "Path/to/file%s" % datetime.now()
example = open(filename, "w")
You can put it in one line if you want:
example = open("Path/to/file%s" % datetime.now(), "w")
But if you're relatively new to programming and to Python, I recommend you keep your small steps broken out until you're more comfortable with things in general.
All the answers posted here identify the problem correctly, that is your string formatting is not correct.
You should also check that the string you end up with is actually a valid file name for the operating system you are trying to create files on.
Your example doesn't generate a valid file name on Windows, and although will work on Linux, the file name created will not be what you expect:
>>> f = open(str(datetime.datetime.now()),'w')
>>> f.write('hello\n')
>>> f.close()
>>> quit()
-rw-r--r-- 1 burhan burhan 6 Sep 11 06:53 2012-09-11 06:53:04.685335
On Windows it doesn't work at all:
>>> open(str(datetime.datetime.now()),'w')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 22] invalid mode ('w') or filename: '2012-09-11 06:51:26.873000'
This would be a better option (2.6+):
filename = "Path/to/file/{0.year}{0.month}{0.day}".format(datetime.now())
For older versions of Python, you can use the classic option:
filename = "Path/to/file/%s" % datetime.strftime(datetime.now(),"%Y%m%d")

Categories

Resources