I'm pretty new to python programming, and I wrote a script to automate uploading a file via SFTP to a remote machine. The script works wonderfully, but there is an issue that I can't seem to figure out. If I'm in the directory in which the file I'm trying to upload is residing, everything goes fine. But, when I type the filename that is not residing in said directory, it doesn't like that. It's a hassle having to browse to different folders each time. I know I can consolidate the files into one folder... But I would love to try and automate this.
The /Downloads directory is hard-coded since that's where most tools reside, does anyone know how I can tweak this line of code to grab the matching file name regardless of the directory the file resides in?
This is what I've written:
#! /usr/bin/python2
# includes
import thirdpartylib
import sys
if len(sys.argv) != 6:
print "Usage: %s file url port username password" % sys.argv[0]
exit(0)
file = sys.argv[1]
host = sys.argv[2]
port = int(sys.argv[3])
username = sys.argv[4]
password = sys.argv[5]
filelocation = "Downloads/%s" % file
transport = thirdpartylib.Transport((host, port))
transport.connect(username=username, password=password)
sftp = thirdpartylib.SFTPClient.from_transport(transport)
sftp.put(file, filelocation)
sftp.close()
transport.close()
First of all, if you're doing any work with filepaths it is recommended that you use some built-in functionality to construct them to ensure that you have proper file separators etc. os.path.join is great for this.
That being said, I would recommend having the user pass in the file path as either an absolute path (in which case it can live anywhere on the machine) or a relative path (in which case it is relative to the current directory). I would not append Downloads/ to all the file paths as that obviously breaks any absolute paths and it requires the individual calling your program to know the internals of it. I think of this as the file path equivalent of a magic number.
So what that boils down to changing the filelocation to simply be the file input argument itself.
filelocation = sys.argv[1]
# You can even do some validation if you want
is not os.path.isfile(filelocation):
print "File '%s' does not exist!" % filelocation
If you really want that Downloads/ folder to be the default (if the file path isn't an absolute path), you can check to see if the input is an absolute path (using os.path.isabs) and if it's not, then specify that it's in the Downloads/ directory.
if not os.path.isabs(filelocation):
filelocation = os.path.join('Downloads', filelocation)
Then users could call your script in two ways:
# Loads file in /absolute/path/to/file
./script.py /absolute/path/to/file ...
# Loads filename.txt from Downloads/filename.txt
./script.py filename.txt ...
Also, it looks like you may have your sftp.put input arguments reversed. The local filename should come first.
I think you want filelocation as the first argument to stfp.put, as that is supposed to be the filename on the local machine. Also, you probably want to put a slash in front of Downloads.
Related
When I write a command line script in python, I'm assuming that it can be invoked from anywhere. This seems to cause incongruity when I want to pass a list of files into the script.
Passing the files using a list or wildcard arguments (whether expanded by bash under *nix or glob.glob with Windows) will return either a relative path or an absolute one, depending on how the file path was described, but this seems to give two different behaviors which have to either be checked or harmonized.
If the script is in the same directory as the files to be imported, this isn't really a problem, but if the script is in a different directory, it seems like you need to grab the absolute path first:
import os,sys,glob
for arg in sys.argv[1:]:
file_list = glob.glob(arg)
for fn in file_list:
print("File Reference: {}".format(os.path.abspath(fn)))
> pwd
/Users/user1/Desktop/script_dir/
> cd ~/Desktop
> script_dir/test.py test_dir/*.csv /Users/user1/Desktop/test_dir/*.txt
File Reference: /Users/user1/Desktop/test_dir/temp1.csv
File Reference: /Users/user1/Desktop/test_dir/temp2.csv
File Reference: /Users/user1/Desktop/test_dir/temp1.txt
File Reference: /Users/user1/Desktop/test_dir/temp2.txt
Assuming the program continued on to do something with the files, it would then manipulate them by absolute path. Is this the correct thing to do here? It seems weirdly klugy, and I can seem to find any references that lay this out.
I'm trying to build a file transfer system with python3 sockets. I have the connection and sending down but my issue right now is that the file being sent has to be in the same directory as the program, and when you receive the file, it just puts the file into the same directory as the program. How can I get a user to input the location of the file to be sent and select the location of the file to be sent to?
I assume you're opening files with:
open("filename","r")
If you do not provide an absolute path, the open function will always default to a relative path. So, if I wanted to open a file such as /mnt/storage/dnd/5th_edition.txt, I would have to use:
open("/mnt/storage/dnd/4p5_edition","r")
And if I wanted to copy this file to /mnt/storage/trash/ I would have to use the absolute path as well:
open("/mnt/storage/trash/4p5_edition","w")
If instead, I decided to use this:
open("mnt/storage/trash/4p5_edition","w")
Then I would get an IOError if there wasn't a directory named mnt with the directories storage/trash in my present folder. If those folders did exist in my present folder, then it would end up in /whatever/the/path/is/to/my/current/directory/mnt/storage/trash/4p5_edition, rather than /mnt/storage/trash/4p5_edition.
since you said that the file will be placed in the same path where the program is, the following code might work
import os
filename = "name.txt"
f = open(os.path.join(os.path.dirname(__file__),filename))
Its pretty simple just get the path from user
subpath = raw_input("File path = ")
print subpath
file=open(subpath+str(file_name),'w+')
file.write(content)
file.close()
I think thats all you need let me know if you need something else.
like you say, the file should be in the same folder of the project so you have to replace it, or to define a function that return the right file path into your open() function, It's a way that you can use to reduce the time of searching a solution to your problem brother.
It should be something like :
import os
filename = "the_full_path_of_the_fil/name.txt"
f = open(os.path.join(os.path.dirname(__file__),filename))
then you can use the value of the f variable as a path to the directory of where the file is in.
I have a program that relies on user input to enter files for the program to open in Python 2.7.11. I have all of those files in a sub-directory called TestCases within the original directory Detector, but I can't seem to access the files in TestCases when running the program from the super-directory. I tried to use os.path.join but to of no avail. Here is my code:
import os.path
def __init__(self):
self.file = None
os.path.join('Detector', 'TestCases')
while self.file == None:
self.input = raw_input('What file to open? ')
try:
self.file = open(self.input, 'r')
except:
print "Can't find file."
My terminal when I run the program goes as follows:
>>> What file to open? test.txt # From the TestCases directory
>>> Can't find file.
>>> What file to open? ...
Am I using os.path.join incorrectly? I thought it was supposed to link the two directories so that files could be accessed from the sub-directory while running the program from the super-directory.
You are using os.path.join('Detector', 'TestCases'), that should return 'Detector/TestCases', but you aren't storing that variable anywhere.
I suppose that you are in Detector directory and you want to open files in TestCases. I that case you can use path join (It concatenates its arguments and RETURNS the result):
import os.path
file = None
while not file:
input = raw_input('What file to open? ')
try:
filepath = os.path.join('TestCases', input)
file = open(filepath, 'r')
except IOError:
print "Can't find " + input
I have stored the result of os.path.join so you could see that it doesn't change the directory, it just concatenates its arguments, maybe you was thinking that function will change the directory, you can do it with os.chdir.
Try it first in a simple script or in the terminal, it will save many headaches.
The documentation about os.path.join
Join one or more path components intelligently. The return value is the concatenation of path...
It seems like you expect it to set some kind of PATH variable or affect the current working directory. For a first start it should be sufficient to add something like this to your code:
open(os.path.join("TestCases",self.input), 'r')
Could someone shed me some lights on the file path matter in Python?
For example my codes need to read a batch of files, the file names are listed and stored in a .txt file, C:\filelist.txt, which content is:
C:\1stfile.txt
C:\2ndfile.txt
C:\3rdfile.txt
C:\4thfile.txt
C:\5thfile.txt
And the codes start with:
list_open = open('c:\\aaa.txt')
read_list = list_open.read()
line_in_list = read_list.split('\n')
all run fine. But if I want to read files in another path, such as:
C:\WorkingFolder\6thfile.txt
C:\WorkingFolder\7thfile.txt
C:\WorkingFolder\8thfile.txt
C:\WorkingFolder\9thfile.txt
C:\WorkingFolder\10thfile.txt
It doesn’t work. I guess the path here C:\WorkingFolder\ is not properly put so Python cannot recognize it.
So in what way I shall put it? Thanks.
hello all,
sorry that maybe i didn't make my self clear.
the problem is, a text file, c:\aaa.txt contains below:
C:\1stfile.txt
C:\WorkingFolder\1stfile.txt
why only C:\1stfile.txt is readable, but the other one not?
The reason your program isn't working is that you're not changing the directory properly. Use os.chdir() to do so, then open the files as normal:
import os
path = "C:\\WorkingFolder\\"
# Check current working directory.
retval = os.getcwd()
print "Current working directory %s" % retval
# Now change the directory
os.chdir( path )
# Check current working directory.
retval = os.getcwd()
print "Directory changed successfully %s" % retval
REFERENCES:
http://www.tutorialspoint.com/python/os_chdir.htm
import os
BASEDIR = "c:\\WorkingFolder"
list_open = open(os.path.join(BASEDIR, 'aaa.txt'))
Simply try using forward slashes instead.
list_open = open("C:/WorkingFolder/6thfile.txt", "rt")
It works for me.
Python has a standard library module ftplib to run FTP communications. It has two means of getting a listing of directory contents. One, FTP.nlst(), will return a list of the contents of a directory given a directory name as an argument. (It will return the name of a file if given a file name instead.) This is a robust way to list the contents of a directory but does not give any indication whether each item in the list is a file or directory. The other method is FTP.dir(), which gives a string formatted listing of the directory contents of the directory given as an argument (or of the file attributes, given a file name).
According to a previous question on Stack Overflow, parsing the results of dir() can be fragile (different servers may return different strings). I'm looking for some way to list just the directories contained within another directory over FTP, though. To the best of my knowledge, scraping for a d in the permissions part of the string is the only solution I've come up with, but I guess I can't guarantee that the permissions will appear in the same place between different servers. Is there a more robust solution to identifying directories over FTP?
Unfortunately FTP doesn't have a command to list just folders so parsing the results you get from ftp.dir() would be 'best'.
A simple app assuming a standard result from ls (not a windows ftp)
from ftplib import FTP
ftp = FTP(host, user, passwd)
for r in ftp.dir():
if r.upper().startswith('D'):
print r[58:] # Starting point
Standard FTP Commands
Custom FTP Commands
If the FTP server supports the MLSD command, then please check that answer for a couple of useful classes (FTPDirectory and FTPTree).
Another way is to assume everything is a directory and try and change into it. If this succeeds it is a directory, but if this throws an ftplib.error_perm it is probably a file. You can catch then catch the exception. Sure, this isn't really the safest, but neither is parsing the crazy string for leading 'd's.
Example
def processRecursive(ftp,directory):
ftp.cwd(directory)
#put whatever you want to do in each directory here
#when you have called processRecursive with a file,
#the command above will fail and you will return
#get the files and directories contained in the current directory
filenames = []
ftp.retrlines('NLST',filenames.append)
for name in filenames:
try:
processRecursive(ftp,name)
except ftplib.error_perm:
#put whatever you want to do with files here
#put whatever you want to do after processing the files
#and sub-directories of a directory here