For my class I have to write code that will receive a pathname and then display the file contents if its a file or display each file and its contents if a directory is the pathname.
I wrote the following code, which works fine when I test it with my own local directory. But when I run the checks on my class portal it returns an error "No such file or directory".
Can anyone help me see what's wrong with my code?
import os
def openFyle(filename):
openFile = open(filename)
return openFile.read()
def displayFiles(filename):
if os.path.isdir(filename):
os.chdir(filename)
print("Directory name:", os.getcwd())
dirLyst = os.listdir(filename)
for file in dirLyst:
if os.path.isfile(file):
return print("File name:", file, openFyle(file))
elif os.path.exists(file) and os.path.isdir(file):
os.chdir(file)
displayFiles(os.getcwd())
else:
print("File name:", filename, openFyle(filename))
def main():
#while True:
filename = input("Enter a pathname: ")
displayFiles(filename)
if __name__ == "__main__":
main()
Using the os module:
import os
def print_all_file_contents(directory):
for root, dirs, files in os.walk(directory):
for file in files:
print(open(os.path.join(root, file)).read())
if __name__ == "__main__":
print_all_file_contents(input("Enter a directory:"))
What I would guess is, one of the tests they're using on your function is to send an invalid path. In your function, you only cover two cases: either its a path or its a file and you print out the file name with its contents. What if you cant find that file? That else should be an elif that does the os.path.isfile, and then an else in case its an invalid path.
This should fix it.
def displayFiles(filename):
if os.path.isdir(filename):
os.chdir(filename)
print("Directory name:", os.getcwd())
dirLyst = os.listdir(filename)
for file in dirLyst:
if os.path.isfile(file):
return print("File name:", file, openFyle(file))
elif os.path.exists(file) and os.path.isdir(file):
os.chdir(file)
displayFiles(os.getcwd())
elif os.path.isfile(filename):
print("File name:", filename, openFyle(filename))
else:
print("Invalid input")
. I think the portal runs automated tests that pass it path names.
Sure, but that doesn't prevent it from giving you invalid input data, such as non-str or Path-like objects or non existing locations
Also, rather than using chdir, create the absolute path as you go using path.join
def displayFiles(filename):
if filename and os.path.exists(filename):
if os.path.isdir(filename):
print("Directory name:", filename)
for file in os.listdir(filename):
child = os.path.join(filename,file)
displayFiles(child)
else:
print("File name:", filename, openFyle(filename))
else:
print("Invalid input")
Almost any time you're working with file system paths in Python, I recommend pathlib, because it's awesome. It doesn't make a huge difference this this case, but getting used to using it will make things much easier when you need to, say, join multiple paths together.
from pathlib import Path
def display_file(path):
print(f'File: {path}\n')
print(path.read_text())
print('\n\n')
if __name__ == '__main__':
path = Path(input('Enter a pathname: '))
if path.is_dir():
for item in path.iterdir():
# This avoids attempting to print hidden files, which may exist
# depending on the OS / filesystem.
if item.is_file() and not item.name.startswith('.'):
display_file(item)
elif path.is_file():
display_file(path)
The code only tries to print contents if the path is in fact a file or a directory; it displays nothing if passed an invalid or nonexistant path.
Related
Selective Copy:
Write a program that walks through a folder tree and searches for
files with a certain file extension (such as .pdf or .jpg). Copy these
files from whatever location they are into a new folder.
I keep getting a traceback error as seen in this screenshot.
I do not know what I am doing wrong.
This is the code I have:
import os, shutil, sys
def selective_copy(src_folder: str = None, ext: str = None, dest_folder: str = None) -> None:
if src_folder is None:
raise AttributeError('src_folder must be given.')
if ext is None:
raise AttributeError('.jpg')
if dest_folder is None:
raise AttributeError('dest_folder must be given.')
src_folder = os.path.abspath(src_folder)
os.chdir(src_folder)
os.mkdir(dest_folder)
# Walk through a folder tree
for foldername, subfolders, filenames in os.walk("./"):
print("Looking in folder: %s..." % foldername)
# Find files with a specific extension
for filename in filenames:
if filename.endswith('.jpg'):
# Copy files to a new folder
print("Copying file: %s..." % filename)
shutil.copy(filename, dest_folder)
print("Done.")
def main():
selective_copy('../', '.jpg', 'new_folder')
if __name__ == '__main__':
main()
Instead of os.mkdir(), I would suggest looking at os.makedirs() (documentation). It has a parameter that I believe you'll find useful for this situation.
I'm trying to loop through some files in a directory. If the filename has two specific strings together, then I'm supposed to open and read those files for information. However, if none of the files have those two strings, I want to print an error message only once.
for filename in os.listdir(directory):
if filename.find("<string1>") != -1 and filename.find("<string2>") != -1:
#open file
else:
#print error message
I know doing this will print as many error messages as there are files in the directory (i.e. if there's 15 files with no matches, I'll get 15 error messages). But what I want is to only print an error message once after there aren't any matches in any of the N files in directory. I figured I could do something like this:
for filename in os.listdir(directory):
if filename.find("<string1>") != -1 and filename.find("<string2>") != -1:
#open file
else:
if filename[-1]: #if filename is last in directory
#print error message
But I've discovered this doesn't work. How would I get an error message to print only after the last filename has been read and doesn't match?
A simple solution would be to initialize some boolean flag before your for loop, e.g. found = false
If you find a file, set found = true. Then you can check the value of found after your for loop finishes and print the appropriate message based on its value.
Filter the list of files before the for-loop:
filenames = [fname for fname in os.listdir(directory)
if '<string1>' in fname and '<string2>' in fname]
if filenames:
for filename in filenames:
#open file
else:
#print error message
You can probably also use the glob module to get the filenames:
import glob
filenames = glob.glob(directory + '/*string1*string2*')
Another way is to use a variable to check if all the files have been processed. Checked and found it working in Python 2.7
import os
directory = "E:\\test\\"
files_count = len(os.listdir(directory))
files_processed = 0
for filename in os.listdir(directory):
if 'string1' in filename and 'string2' in filename:
#open file
print ("Opening file")
else:
files_processed = files_processed + 1
if (files_processed >= files_count):
print ("error message")
Not sure if this is extreme. But I'd make it a function and raise IOError.
Plus, i'd always use absolute path. Try the pathlib module too
import os
def get_files(directory):
for filename in os.listdir(directory):
if "string1" in filename and "string2" in filename:
yield filename
raise IOError("No such file")
for file in get_files('.'):
print(file)
# do stuff with file
I wanted to supply python with a windows 'data path' that could be used to set up input processing. I googled this with no luck, and now figure I am on my own.
There appears to be many ways of reading in a file with python, and after some frustration with "\" and "/" and windows path names I found a way to get my data path set up. It is not a general approach but should serve me well.
Related Questions: Is this code ugly? Is this a nonstandard method? Are there elegant features in 3.6 that should be used?
### Title: Process an input file using a 'data path' for a user on windows
import sys
import os
print("OK, starting program...")
file_processed = False
for path, dirs, files in os.walk("/Users/Mike"):
if file_processed: break
for file in files:
if file_processed: break
if file == 'seriousdata.txt':
my_path = os.path.abspath(path)
my_dsn = os.path.join(my_path, file)
print("Opening txt file " + my_dsn + " for input.")
with open(my_dsn) as da_lines:
textlines = (line.rstrip('\r\n') for line in da_lines)
for line in textlines:
print(line)
file_processed = True
if file_processed:
pass
else:
print("File not found")
print("OK, program execution has ended.")
sys.exit() # END SAMPLE CODE SNIPPET
From looking at your code, I'm assuming that you want to start at one directory, and move through each child directory, printing out the matching filename's contents if it is found.
If so, then this is way to do this with recursion:
import os
def recursive_list(path, filename):
files = os.listdir(path)
for name in files:
try:
p = os.path.join(path, name)
if os.path.isdir(p):
recursive_list(p, filename)
else:
if name == filename:
with open(p, "r") as f:
print(f.read())
except PermissionError:
pass
return
recursive_list("/home/jebby/Desktop","some_file.txt")
This will start out listing files in path. For every file that is found, if that file is a directory, then the function itself is called (Starting at the path to that folder). If filename matches the name of any file in the current directory, it will be printed (if the user has permissions for that file).
Otherwise, if you only want to read the filename from a known directory without walking down the directory tree:
import os
data_path = "/home/jebby/Desktop"
file_you_want = "filename.txt"
with open(os.path.join(data_path, file_you_want), "r") as f:
content = f.read()
print(content)
The main question would be : Do you know the location of the file?
Jebby has an answer to crawl through the directories.
Here is a solution without using "import os"
dir_fullpath = "c:/project_folder/data"
dir_path = "data"
filename = "file.txt"
try:
f = open(dir_path + "/" + filename, 'r')
# print("open " +dir_path + "\" + filename)
# data=[]
for line in f:
print (line.rstrip())
# data.append(line.rstrip())
f.close()
except IOError:
print("Fail to open" + dir_path + "\" + filename)
How can I loop this code so that it asks the user to search for another file if the file has not been found?
import os, sys
from stat import *
from os.path import join
lookfor = input("\nPlease enter file name you want to search? \n")
def search(directory):
for files in os.listdir(directory):
fileItem = os.path.join(directory, files)
fileItemStatInfo = os.stat(fileItem)
if S_ISDIR(fileItemStatInfo.st_mode):
search(fileItem)
elif S_ISREG(fileItemStatInfo.st_mode):
print("Searching", fileItem)
if lookfor in files:
print("\nThe File Has Been Found: %s" % join(directory, lookfor))
break
First, you need to make search return success or failure:
def search(directory):
for files in os.listdir(directory):
fileItem = os.path.join(directory, files)
fileItemStatInfo = os.stat(fileItem)
if S_ISDIR(fileItemStatInfo.st_mode):
return search(fileItem)
elif S_ISREG(fileItemStatInfo.st_mode):
print("Searching", fileItem)
if lookfor in files:
print("\nThe File Has Been Found: %s" % join(directory, lookfor))
return True
(Note that if we fall off the end of the for loop, we'll fall off the end of the function, which means we return None. Therefore, the function an only return True, with is truthy, or None, which is not.)
Now, you just loop until it returns something true:
while True:
lookfor=input("\nPlease enter file name you want to search? \n")
if search(lookfor):
break
print('Could not find that file, sorry. Try again.')
All that said, I don't think search does what you want it to—and you can simplify it tremendously, too.
First, I'm not sure whether you're trying to use lookfor as a global variable, or as a closure within the search function… but either way, you probably shouldn't be doing that. Pass it as an argument.
Also, having a variable named files that holds each filename, instead of a collection of them, is very confusing.
If you want to walk a directory tree recursively, use os.walk instead of trying to implement it yourself.
And you should probably be printing out the found filename, not the looked-for fragment.
Putting that together:
def search(lookfor, directory):
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
if lookfor in filename:
print("\nThe File Has Been Found: %s" % join(dirpath, filename))
return True
Of course in most real-life code, you'll probably want to return the pathname, so the rest of your code can use it (e.g., to open the file), instead of just printing it out:
def search(lookfor, directory):
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
if lookfor in filename:
return join(dirpath, filename)
while True:
lookfor=input("\nPlease enter file name you want to search? \n")
path = search(lookfor)
if path:
break
print('Could not find that file, sorry. Try again.')
with open(path) as f:
pass # now we can actually use the file we searched so hard for
I'm trying to delete old SVN files from directory tree. shutil.rmtree and os.unlink raise WindowsErrors, because the script doesn't have permissions to delete them. How can I get around that?
Here is the script:
# Delete all files of a certain type from a direcotry
import os
import shutil
dir = "c:\\"
verbosity = 0;
def printCleanMsg(dir_path):
if verbosity:
print "Cleaning %s\n" % dir_path
def cleandir(dir_path):
printCleanMsg(dir_path)
toDelete = []
dirwalk = os.walk(dir_path)
for root, dirs, files in dirwalk:
printCleanMsg(root)
toDelete.extend([root + os.sep + dir for dir in dirs if '.svn' == dir])
toDelete.extend([root + os.sep + file for file in files if 'svn' in file])
print "Items to be deleted:"
for candidate in toDelete:
print candidate
print "Delete all %d items? [y|n]" % len(toDelete)
choice = raw_input()
if choice == 'y':
deleted = 0
for filedir in toDelete:
if os.path.exists(filedir): # could have been deleted already by rmtree
try:
if os.path.isdir(filedir):
shutil.rmtree(filedir)
else:
os.unlink(filedir)
deleted += 1
except WindowsError:
print "WindowsError: Couldn't delete '%s'" % filedir
print "\nDeleted %d/%d files." % (deleted, len(toDelete))
exit()
if __name__ == "__main__":
cleandir(dir)
Not a single file is able to be deleted. What am I doing wrong?
To remove recursively all .svn I use this script. May be it will help someone.
import os, shutil, stat
def del_evenReadonly(action, name, exc):
os.chmod(name, stat.S_IWRITE)
os.remove(name)
for root, subFolders, files in os.walk(os.getcwd()):
if '.svn' in subFolders:
shutil.rmtree(root+'\.svn',onerror=del_evenReadonly)
Subversion usually makes all the .svn directories (and everything in them) write protected. Probably you have to remove the write protection before you can remove the files.
I'm not really sure how to do this best with Windows, but you should be able to use os.chmod() with the stat.S_IWRITE flag. Probably you have to iterate through all the files in the .svn directories and make them all writable individually.