How do I read from a file in the same directory? - ruby

I'm very much a beginner. I'd like to learn to read and write a file. Here's what I'm trying.
rdfile = File.open('bhaarat.txt', 'r+')
Unfortunately, this is returning "C:/directoriesblahblah/ubuntu3.rb:1:in 'initialize': No such file or directory - bhaarat.txt (Errno::ENOENT)
I have found solutions but I am not only new to Ruby but new to programming in general so I couldn't get an answer that made sense to me out of those.
Thanks in advance!

To obtain the path to the current file, you can use:
__FILE__
To obtain the directory in which the current file exists, you can use:
File.dirname(__FILE__)
To create a path from strings, you can use:
File.join('part1', 'part2', ...)
Therefore, to create a path to a file in that directory, you can use:
File.join(File.dirname(__FILE__), 'filename')
If your file name is bhaarat.txt, the above becomes:
File.join(File.dirname(__FILE__), 'bhaarat.txt')
If you replace that in your code, you will get:
rdfile = File.open(File.join(File.dirname(__FILE__), 'bhaarat.txt'), 'r+')
You can also make this a separate variable, if you want, to make the code more readable:
path = File.join(File.dirname(__FILE__), 'bhaarat.txt')
rdfile = File.open(path, 'r+')

The file is searched in the current directory, not the directory where the script is located.
C:\> ruby scripts\ubuntu3.rb
No such file or directory - bhaarat.txt
Move to the file location first and then run the script. For example, if the file is located in the same directory with the script:
C:\> cd scripts
C:\scripts> ruby ubuntu3.rb

File.read(File.join(__dir__, 'filename'))

Found something that did the trick. Searched a little harder and found this:
I changed my original code
rdfile = File.open('bhaarat.txt', 'r+')
to
rdfile = File.open(File.join(File.dirname(__FILE__),'bhaarat.txt'), 'r+')
and that makes it look in the directory of your .rb file, instead of the directory that your command prompt is currently in.

Related

How to get filepath to file in another folder unix?

I am trying to write some data in one Ruby file to a file in another folder but I am having trouble identifying the path to get to the file I want to write to.
My current code is:
File.write('../csv_fixtures/loans.csv', 'test worked!')
And my folder structure is as follows:
Where I am trying to run my code in 'run_spec.rb' and write to 'loans.csv'.
Additionally, this is the error I am getting:
Give the path relative to the working directory, not the file that you call File.write from. The working directory is the place you've navigated to through cd before calling the ruby code. If you ran rspec from the root of your project, then the working directory will also be the root. So, in this case, it looks like it would be ./spec/csv_fixtures/loans.csv. You can run puts Dir.pwd to see the working directory that all paths should be relative to.
If you wanted to something more like require_relative, you have to use some sort of workaround to turn it into an absolute path, such as File.dirname(__FILE__) which gives the absolute path of the folder containing the current file:
path = File.join(File.dirname(__FILE__, "../csv_fixtures/loans.csv"))

How to find text file in same directory

I am trying to read a list of baby names from the year 1880 in CSV format. My program, when run in the terminal on OS X returns an error indicating yob1880.txt doesnt exist.
No such file or directory # rb_sysopen - /names/yob1880.txt (Errno::ENOENT)
from names.rb:2:in `<main>'
The location of both the script and the text file is /Users/*****/names.
lines = []
File.expand_path('../yob1880.txt', __FILE__)
IO.foreach('../yob1880.txt') do |line|
lines << line
if lines.size >= 1000
lines = FasterCSV.parse(lines.join) rescue next
store lines
lines = []
end
end
store lines
If you're running the script from the /Users/*****/names directory, and the files also exist there, you should simply remove the "../" from your pathnames to prevent looking in /Users/***** for the files.
Use this approach to referencing your files, instead:
File.expand_path('yob1880.txt', __FILE__)
IO.foreach('yob1880.txt') do |line|
Note that the File.expand_path is doing nothing at the moment, as the return value is not captured or used for any purpose; it simply consumes resources when it executes. Depending on your actual intent, it could realistically be removed.
Going deeper on this topic, it may be better for the script to be explicit about which directory in which it locates files. Consider these approaches:
Change to the directory in which the script exists, prior to opening files
Dir.chdir(File.dirname(File.expand_path(__FILE__)))
IO.foreach('yob1880.txt') do |line|
This explicitly requires that the script and the data be stored relative to one another; in this case, they would be stored in the same directory.
Provide a specific path to the files
# do not use Dir.chdir or File.expand_path
IO.foreach('/Users/****/yob1880.txt') do |line|
This can work if the script is used in a small, contained environment, such as your own machine, but will be brittle if it data is moved to another directory or to another machine. Generally, this approach is not useful, except for short-lived scripts for personal use.
Never put a script using this approach into production use.
Work only with files in the current directory
# do not use Dir.chdir or File.expand_path
IO.foreach('yob1880.txt') do |line|
This will work if you run the script from the directory in which the data exists, but will fail if run from another directory. This approach typically works better when the script detects the contents of the directory, rather than requiring certain files to already exist there.
Many Linux/Unix utilities, such as cat and grep use this approach, if the command-line options do not override such behavior.
Accept a command-line option to find data files
require 'optparse'
base_directory = "."
OptionParser.new do |opts|
opts.banner = "Usage: example.rb [options]"
opts.on('-d', '--dir NAME', 'Directory name') {|v| base_directory = Dir.chdir(File.dirname(File.expand_path(v))) }
end
IO.foreach(File.join(base_directory, 'yob1880.txt')) do |line|
# do lines
end
This will give your script a -d or --dir option in which to specify the directory in which to find files.
Use a configuration file to find data files
This code would allow you to use a YAML configuration file to define where the files are located:
require 'yaml'
config_filename = File.expand_path("~/yob/config.yml")
config = {}
name = nil
config = YAML.load_file(config_filename)
base_directory = config["base"]
IO.foreach(File.join(base_directory, 'yob1880.txt')) do |line|
# do lines
end
This doesn't include any error handling related to finding and loading the config file, but it gets the point across. For additional information on using a YAML config file with error handling, see my answer on Asking user for information, and never having to ask again.
Final thoughts
You have the tools to establish ways to locate your data files. You can even mix-and-match solutions for a more sophisticated solution. For instance, you could default to the current directory (or the script directory) when no config file exists, and allow the command-line option to manually override the directory, when necessary.
Here's a technique I always use when I want to normalize the current working directory for my scripts. This is a good idea because in most cases you code your script and place the supporting files in the same folder, or in a sub-folder of the main script.
This resets the current working directory to the same folder as where the script is situated in. After that it's much easier to figure out the paths to everything:
# Reset working directory to same folder as current script file
Dir.chdir(File.dirname(File.expand_path(__FILE__)))
After that you can open your data file with just:
IO.foreach('yob1880.txt')

ruby: Can't create new file

I have a command line program that asks the user a set of questions and stores them in a file. The only problem is, I need it to create a new file and it won't.
Here is what I have tried:
File.open("path/to/file", "w")and File.open("path/to/file", "w+")
Both times I get this error
in 'initialize': No such file or directory # rb_sysopen - path/to/file (Errno::ENOENT)
Here is my current code:
File.open("path/to/file", "w") { |f| f.write(array.join("\n")) }
When someone writes path/to/file in a blog post or documentation, they don't intend for you to literally write path/to/file in your code. The point is that you need to edit that string to actually have the real path to your file, either as a relative path or an absolute path.
You said you are getting this error from the Ruby interpreter:
No such file or directory # rb_sysopen - path/to/file (Errno::ENOENT)
This means that in the current working directory, there is no directory named "path", or if there is a directory named "path", then it doesn't have a child directory named "to".
You could solve the immediate problem by running mkdir -p path/to, but that would be weird. It is better to just write an appropriate path in your code, pointing to a directory that already exists. Try changing the path to simply be output.txt (without any slashes) and see how that works.
Ensure you are using an absolute path, and if so, make sure the directory you want to store the file in is missing. Try creating it first:
require 'fileutils'
FileUtils.mkdir_p '/path/to'
File.open('/path/to/file', 'w') { ... }

How can I create a file on my desktop from a Ruby script?

I'm building a webcrawler and I want it to output to a new file that is timestamped. I've completed what I thought would be the more difficult part but I cannot seem to get it to save to the desktop.
Dir.chdir "~/Desktop"
dirname = "scraper_out"
filename = "#{time}"
Dir.mkdir(dirname) unless File.exists?(dirname)
Dir.chdir(dirname)
File.new(filename, "w")
It errors out on the first line
`chdir': No such file or directory # dir_chdir - ~/Desktop
I've read the documentation on FileUtils, File and cannot seem to find where people change into nested directories from the root.
Edit: I don't think FileUtils understands the ~.
~/ is not recognized by Ruby in this context.
Try:
Dir.chdir ENV['HOME']+"/Desktop"
This might help you
Create a file in a specified directory

File paths in Ruby

So I want to make a file path relative to the directory it is in, in Ruby.
I have a project, and I want it to be able to find the file no matter what directory the project is unzipped into. (Say the code is run on different machines, for example) I can't figure it out for the life of me.
It seems for requires that I can do this:
require File.dirname(__FILE__) + '/comparison'
What can I do for a file that is in a different directory than my src folder?
Instead of listing,
file = 'C:/whole path/long/very_long/file.txt'
I'd like to say:
file = 'file.txt'
or
file = File.helpful_method + 'file.txt'
file = File.join(File.dirname(__FILE__), '..', 'another_dir', 'file.txt')
Replace '..', 'another_dir' with the relative path segments that reach 'file.txt'.
If you're running Ruby 1.9.2 or later, you can use require_relative instead:
require_relative '../somewhere/file.rb'
This doesn't solve the general problem of referring to files by their relative path, but if all you're doing is requiring the file, it should work.

Resources