I am getting the following error:
"Errno::ENOENT: No such file or directory"
when I try to download a file into a directory that does not exist.
For example:
ftp = Net::FTP.new('example.com')
ftp.login
files = ftp.chdir('pub/lang/ruby/contrib')
files = ftp.list('n*')
ftp.getbinaryfile('nif.rb-0.91.gz', 'pub/lang/ruby/contrib/nif.gz', 1024)
ftp.close
However, for many of the files I will be downloading, the full directory path will not exist. For example, until the first file creates pub, it won't exist and this goes for lang/ruby/contrib too.
Is there a method that can check if directories exist and if not create them? I know that there is exist?, but that looks to reference files and it does not create the full path. I figure I need some recursive method to traverse down the folder structure until it hits the filename.
EDIT: mkdir_p seems to be exactly the solution I need.
However, when I use a path of "/a/b/c" I noticed that FileUtils.mkdir_p(File.dirname(localdir)) returns an error: Errno::EACCES: Permission denied - /a
If I remove the "/" in front manually it works. What is causing this? What is the best solution for resolving the error? should I just use the following?
path="/a/b/c"
if path[0]="/"
path=path[1..-1]
end
However, I feel like this is just a hack.
You can't save to a non-existing path. As the developer you're responsible to make sure your destination paths exist prior to trying to save the file.
Ruby has methods that let you check for the existence a file or directory:
FileUtils.makedirs()
is an alias to mkpath
, and mkdir_p
. I prefer makedirs
because it's a mnemonic.
These will also be useful:
Between those two I prefer Dir.chdir
, because it takes a block. Any actions that occur inside that block happen in the directory you changed to. At exit, the directory reverts to what it was previously.
The analog of *nix mkdir -p, mkdir_p, is what you need, which was provided in the other two answers, but I didn't see anyone address your edit about permissions.
The solution is the user invoking your script requires write permission on the root directory.
The path, "/a/b/c", is addressing the root path ("/"). This is typically only write accessible to the root user or a user that has sudo access.
When you modified the path to remove the leading "/", you told mkdir_p to create the directories "a/b/c" relative to the current working directory instead of relative to the root directory. The reason the modified version works is because the user invoking your ruby script has write permission on the current working directory.
As a personal aside, if consumers of your script are providing the path input, then you probably don't want to remove leading slashes as that can create files/directories in a drastically different place from where the user expects...unless that is the purpose of your program, but make that clear up front.
References:
I got here because I had gem installed but the file was not installed on the machine. In my case, I had gem espeak-ruby
gem was installed but it was not installed on my mac so I installed that with simple brew install espeak
command and restarted the server. My recommendation to you us make sure everything is installed properly.
In the fileutils module you can use mkdir_p
which is similar to the mkdir -p
command which creates the full path if it doesn't already exist.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With