I'm trying to prepend text to an existing file.. This code works just great, BUT the last line never seems to execute. I can delete the original file, but the file is never renamed from the new temp file back to the original filename...
I'm sure it's something easy, but, I don't know why it doesn't work. Can anyone help?
# grab input text
s = "{query}"
# create insert value in template with timestamp
tmp = "#{Time.now.strftime('%Y-%m-%d %I:%M %p')}\n#{s}"
# path to file you wish to append...
# folder path must exist, file will be created if it doesn't
o = File.expand_path("~/Dropbox/Notes/1scratchpad.txt")
n = File.expand_path("~/Dropbox/Notes/1scratchpad.new.txt")
# open file in append mode and add the string
File.open(n, 'w') do |n|
n.puts tmp
n.puts "\n"
File.foreach(o) do |li|
n.puts li
end
end
File.delete(o)
File.rename(n, o)
Try this
# grab input text
s = "{query}"
# create insert value in template with timestamp
tmp = "#{Time.now.strftime('%Y-%m-%d %I:%M %p')}\n#{s}"
# path to file you wish to append...
# folder path must exist, file will be created if it doesn't
o = File.expand_path("~/Dropbox/Notes/1scratchpad.txt")
n = File.expand_path("~/Dropbox/Notes/1scratchpad.new.txt")
# open file in append mode and add the string
File.open(n, 'a') do |n|
n << tmp
n << "\n"
n << File.read(o)
end
#File.delete(o)
## Delete is no longer rename would take care of everthing
File.rename(n, o)
Related
I want to export sc files from SpaceEngine, then for each file, create a new file with the same name but with the extension .txt.
Here is my code:
require 'fileutils'
require 'IO/console'
puts "Make sure your export folder is clear of everything but the files you want to turn into Object text files."
puts "Starting Process"
i = 0
Dir.foreach('C:\SpaceEngine\export') do |item|
next if item == '.' or item == '..'
i = i + 1
name = File.basename(item, ".*")
current = File.new("#{name}.txt", "w");
current.close
end
sleep 2
I have the latter part already, but I can't get it to read the original files one by one, and then only put certain things from the original into the new file.
# test.sc
# assume this is your test data
this has foo
this does not
this also has foo
this has some other stuff
this is the last line which has foo
blah
blah blah 💩
# filejunk.rb
# you need to write a method that handles the data inside the file you want to
# modify, change, replace etc. but for example
def replace_file_data(filename)
lines = File.readlines
lines.select{|l| l.include?'foo'} #assumes you only want lines with 'foo' in them
end
Dir.glob('C:\SpaceEngine\export\*.sc').each_with_index do |filename, i|
i += 1
name = File.basename(filename, ".*")
current = File.new("#{name}.txt", "w") {|f| f.write replace_file_data(filename) }
current.close
end
I'm having a bit of trouble searching through a file and editing certain parameters of the file. The code is below
file_names = ["#{fileNameFromUser}"]
file_names.each do |file_name|
text = File.read(file_name)
replacedcontent = text.gsub(/textToReplace/, "#{ReplaceWithThis}")
replacedcontent += text.gsub(/textToReplace2/, "#{ReplaceWithThis2}")
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts replacedcontent}
end
so right now what it does is that it print the contents of the file twice and I can only assume its because its inside the do loop. My end goal here is that the file has textToReplace and textToReplace2 and I need it to read through the file, replaced both with whatever the user inputs and save/write changes to the file.
it print the contents of the file twice and I can only assume its because its inside the do loop
Nope, it's because you append it twice:
text = first_replacement_result
text += second_replacement_result
There's two ways to do this: one with mutation:
text.gsub!(...) # first replacement that changes `text`
text.gsub!(...) # second replacement that changes `text` again
or chained replacement:
replacedcontent = text.gsub(...).gsub(...) # two replacements one after another
You will need to re-use replacedcontent instead of concatenating it to avoid printing it twice.
file_names = ["#{fileNameFromUser}"]
file_names.each do |file_name|
text = File.read(file_name)
replacedcontent = text.gsub(/textToReplace/, "#{ReplaceWithThis}")
replacedcontent = replacedcontent.gsub(/textToReplace2/, "#{ReplaceWithThis2}")
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts replacedcontent}
end
OR
replacedcontent = text.gsub(/textToReplace/, "#{ReplaceWithThis}").gsub(/textToReplace2/, "#{ReplaceWithThis2}")
I am trying to write a script to do the following:
There are two directories A and B. In directory A, there are files called "today" and "today1". In directory B, there are three files called "today", "today1" and "otherfile".
I want to loop over the files in directory A and append the files that have similar names in directory B to the files in Directory A.
I wrote the method below to handle this but I am not sure if this is on track or if there is a more straightforward way to handle such a case?
Please note I am running the script from directory B.
def append_data_to_daily_files
directory = "B"
Dir.entries('B').each do |file|
fileName = file
next if file == '.' or file == '..'
File.open(File.join(directory, file), 'a') {|file|
Dir.entries('.').each do |item|
next if !(item.match(/fileName/))
File.open(item, "r")
file<<item
item.close
end
#file.puts "hello"
file.close
}
end
end
In my opinion, your append_data_to_daily_files() method is trying to do too many things -- which makes it difficult to reason about. Break down the logic into very small steps, and write a simple method for each step. Here's a start along that path.
require 'set'
def dir_entries(dir)
Dir.chdir(dir) {
return Dir.glob('*').to_set
}
end
def append_file_content(target, source)
File.open(target, 'a') { |fh|
fh.write(IO.read(source))
}
end
def append_common_files(target_dir, source_dir)
ts = dir_entries(target_dir)
ss = dir_entries(source_dir)
common_files = ts.intersection(ss)
common_files.each do |file_name|
t = File.join(target_dir, file_name)
s = File.join(source_dir, file_name)
append_file_content(t, s)
end
end
# Run script like this:
# ruby my_script.rb A B
append_common_files(*ARGV)
By using a Set, you can easily figure out the common files. By using glob you can avoid the hassle of filtering out the dot-directories. By designing the code to take its directory names from the command line (rather than hard-coding the names in the script), you end up with a potentially re-usable tool.
My solution....
def append_old_logs_to_daily_files
directory = "B"
#For each file in the folder "B"
Dir.entries('B').each do |file|
fileName = file
#skip dot directories
next if file == '.' or file == '..'
#Open each file
File.open(File.join(directory, file), 'a') {|file|
#Get each log file from the current directory in turn
Dir.entries('.').each do |item|
next if item == '.' or item == '..'
#that matches the day we are looking for
next if !(item.match(fileName))
#Read the log file
logFilesToBeCopied = File.open(item, "r")
contents = logFilesToBeCopied.read
file<<contents
end
file.close
}
end
end
Below is the piece of code that is supposed read the directory and for each file entry prints the first row of the file. The issue is x is not visible so file is not being parsed.
Dir.foreach("C:/fileload/src") do |file_name|
x = file_name
puts x
f = File.open("C:/fileload/src/" +x)
f.readlines[1..1].each do |line|
puts line
end
end
Why are you assigning x to file_name? You can use file_name directly. And if you are only reading the first line of the file, why not try this?
#!/usr/bin/ruby
dir = "C:/fileload/src"
Dir.foreach(dir) do |file_name|
full = File.join(dir, file_name)
if File.file?(full)
f = File.open(full)
puts f.first
f.close
end
end
You should use File.join to safely combine paths in Ruby. I also checked that you are opening a file using the File.file? method.
You have no visibility issue with x. You should be using File::join or Pathname#+ to build your file paths. You should exclude non-files from consideration. You're selecting the second line, not the first with [1..1]. Here's a cleaner correct replacement for your sample code.
dir = "C:/fileload/src"
Dir.foreach(dir).
map { |fn| File.join(dir,fn) }.
select { |fn| File.file?(fn) }.
each { |fn| puts File.readlines(fn).first }
The Ruby script i am writing is going to be run every morning and will pull information about backup files and write them to a csv file. This file has column names on the first line.
I have gotten it to work by appending to the end of the file:
open("#{curDir}/Backup_Times.csv", 'a') do |f|
...
end
I would like to see the newest data first without having to sort in Excel.
In Ruby, is there a way to write this data starting at the 2nd line of the file?
You write a new file, applying your change at the desired line, then rename result back to the original file name. The following method will copy the file and yield the output file object to a block at the correct line, so that block can output your new lines.
def insert_lines_following_line file, line_no
tmp_fn = "#{file}.tmp"
File.open( tmp_fn, 'w' ) do |outf|
line_ct = 0
IO.foreach(file) do |line|
outf.print line
yield(outf) if line_no == (line_ct += 1)
end
end
File.rename tmp_fn, file
end
insert_lines_following_line( "#{curDir}/Backup_Times.csv", 1 ) do |outf|
# output new csv lines in this block
outf.puts ['foo','bar','baz',1,2,3].join(",") # or however you build your csv line
end