writing into a .txt file, without renaming the first line - lua

How I can write in a file, without replacing the first line?
I tried
file = io.open('test123.txt', 'r+')
file:write('test')
file:close()
but instead of creating a new line, it rewrites the first line

Try this:
file = io.open('test123.txt', 'r+')
file:read('L')
file:flush()
file:write('test')
file:close()
That keeps the first line as-is, and then starts overwriting after that. If it gets to the end, then it will start to grow the file.

Related

Why the lua function io.write() did not work. It only display the results on the terminal, rather than writing to a file

I am learning the Lua IO library. I'm having trouble with io.write(). In Programming Design in Lua, there is a piece of code that iterates through the file line by line and precedes each line with a serial number.
This is the file I`m working on:
test file: "iotest.txt"
This is my code
io.input("iotest.txt")
-- io.output("iotest.txt")
local count = 0
for line in io.lines() do
count=count+1
io.write(string.format("%6d ",count), line, "\n")
end
This is the result of the terminal display, but this result cannot be written to the file, whether I add IO. Output (" iotest.txt ") or not.
the results in terminal
This is the result of file, we can see there is no change
The result after code running
Just add io.flush() after your write operations to save the data to the file.
io.input("iotest.txt")
io.output("iotestout.txt")
local count = 0
for line in io.lines() do
count=count+1
io.write(string.format("%6d ",count), line, "\n")
end
io.flush()
io.close()
Refer to Lua 5.4 Reference Manual : 6.8 - Input and Output Facilities
io.flush() will save any written data to the output file which you set with io.output
See koyaanisqatsi's answer for the optional use of file handles. This becomes especially useful if you're working on multiple files at a time and gives you more control on how to interact with the file.
That said you should also have different files for input and output. You'll agree that it doesn't make sense to read and write from and to the same file alternatingly.
For writing to a file you need a file handle.
This handle comes from: io.open()
See: https://www.lua.org/manual/5.4/manual.html#6.8
A file handle has methods that acts on self.
Thats the function after the : at file handle.
So io.write() puts out on stdout and file:write() in a file.
Example function that can dump a defined function to a file...
fdump=function(func,path)
assert(type(func)=="function")
assert(type(path)=="string")
-- Get the file handle (file)
local file,err = io.open(path, "wb")
assert(file, err)
local chunk = string.dump(func,true)
file:write(chunk)
file:flush()
file:close()
return 'DONE'
end
Here are the methods, taken from io.stdin
close = function: 0x566032b0
seek = function: 0x566045f0
flush = function: 0x56603d10
setvbuf = function: 0x56604240
write = function: 0x56603e70
lines = function: 0x566040c0
read = function: 0x56603c90
This makes it able to use it directly like...
( Lua console: lua -i )
> do io.stdout:write('Input: ') local result=io.stdin:read() return result end
Input: d
d
You are trying to open the same file for reading and writing at the same time. You cannot do that.
There are two possible solutions:
Read from file X, iterate through it and write the result to another file Y.
Read the complete file X into memory, close file X, then delete file X, open the same filename for writing and write to it while iterating through the original file (in memory).
Otherwise, your approach is correct although file operations in Lua are more often done using io.open() and file handles instead of io.write() and io.read().

Lua io.write() not working

I am using a luvit Lua environment to run my lua code through my control panel. I am looking to write to a .txt file, but with the simple code that i am running, its not working.
The reason I wish to write to a .txt file is to log notices from my Discord Bot I am working on in the Discordia library.
I have a folder called MezzaBOT. In this file i have a write.lua file and also a log.txt file. I have this simple code in my write.lua file:
io.output('log.txt')
io.write('hello\n')
io.close()
I then run in my command promt with Luvit environment:
>luvit Desktop\mezzabot\write.lua
I don't get any errors but the log.txt file continues to stay empty. Am I missing a line in my code, or do i need to access log.txt differently?
edit: my new code is the following
file = io.open('log.txt')
file:write('hello', '\n')
file:close()
and it is not making a new line for each time with \n
edit B:
Ok, i found my problem, its creating a log.txt in my C:\Users\PC.
One other problem is when writing, its not making a new line with the \n. Can someone please help me?
Lua, by default, opens files in read mode. You need to explicitly open a file in write mode if you want to write to it (see manual)
file = io.open('log.txt', 'w')
file:write('hello', '\n')
file:close()
Should work :)

Not able to create a file for writing

I am uploading txt files using carrierwave. The files are not small (80 MB - 500 MB) and I want to remove some of the lines to reduce this size (about 80% of the file size is going to be reduced).
I have created a model method in order to clear these lines:
require 'fileutils'
def clear_unnecessary_lines
old_file_path = Rails.root.join('public').to_s + log_file.to_s
new_file_path = old_file_path.sub! '.txt', '_temp.txt'
File.open(old_file_path, 'r') do |old_file|
File.open(new_file_path, 'w') do |new_file|
old_file.each_line do |line|
new_file.write(line) unless line.grep(/test/).size > 0
end
end
end
FileUtils.mv new_file_path, old_file_path
end
but I am getting error when I am trying to open the new file saying there is no such file. As I have read opening a file with the w option should create an empty file for writing. Then why I am getting such error?
Also, since log_file column is holding the path to the original file, and I am changing it, could you tell how to rename the new file with the old name? As I have checked I should specify only old and new names, not paths.
Errno::ENOENT: No such file or directory - /home/gotqn/Rails/LogFilesAnalyser/LogFilesAnalyser/public/uploads/log_file/log_file/3/log_debug_temp.txt
It is strange that If I execute the following command in rails console, it is not throwing an error and the file is created.
File.open('/home/gotqn/Rails/LogFilesAnalyser/LogFilesAnalyser/public/uploads/log_file/log_file/3/log_debug_temp.txt','w')
Ah, i see your problem now. When you do this
new_file_path = old_file_path.sub! '.txt', '_temp.txt'
you call the "self-altering" version of sub, ie sub!. This will actually change the value of old_file_path as a side effect. Then, in the next line, you try to open this file, which hasn't been created yet. Take out the exclamation mark and you should be fine.

CSV.open(..) block does not execute, and ends immediately

I am opening a CSV file for writing with the following code, as indicated in CSV documentation here (http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV.html):
CSV.open( csv_file_out, 'wb' ) { |csv_line_out|
#stuff happens here
}
the block does not execute, i.e. after the CSV.open command debugger goes directly to the end of block.
thinking "just in case", I try the same with IO modes w+b wt w+t ab a+b. I also tried creating the file before the in case there was a problem with opening it. nothing changes.
when I stop the debugger at the CSV.open line, I am able to execute a block manually and create a csv file myself. I can also create the file frmo the exact same command from console. But it won't work when executed in the server.
Any ideas on what's going on are very welcome. Thanks in advance!
You don't need the {} brackets before your |csv_line_out|
Your trying to iterate sth. (the files content) that does not exist so its logical that it ends imediatly! Try it this way:
CSV.open(csv_file_out, "wb") do |csv|
csv << [column1, column2,...]
end

How to insert a string into a textfile

I have a configuration file to which I want to add a string, that looks e.g. like that:
line1
line2
line3
line4
The new string should not be appended but written somewhere into the middle of the file. Therefore I am looking for a specific position (or string) in the file and when it has been found, I insert my new string:
file = File.open(path,"r+")
while (!file.eof?)
line = file.readline
if (line.downcase.starts_with?("line1"))
file.write("Some nice little sentence")
end
end
The problem is that Ruby overwrites the line in that position with the new text, so the result is the following:
line1
Some nice little sentence
line3
line4
What I want is a "real" insertion:
line1
Some nice little sentence
line2
line3
line4
How can this be achieved?
If it's a small file I think the easiest way would be to:
Read the complete file.
Insert the line.
Write the new file.
That is the way Rails does it behind the scenes.
Or you can copy it line by line and then overwrite the original with mv like this:
require 'fileutils'
tempfile=File.open("file.tmp", 'w')
f=File.new("file.txt")
f.each do |line|
tempfile<<line
if line.downcase=~/^line2/
tempfile << "Some nice little sentence\n"
end
end
f.close
tempfile.close
FileUtils.mv("file.tmp", "file.txt")
def replace(filepath, regexp, *args, &block)
content = File.read(filepath).gsub(regexp, *args, &block)
File.open(filepath, 'wb') { |file| file.write(content) }
end
replace(my_file, /^line2/mi) { |match| "Some nice little sentence"}
line1
Some nice little sentence
line2
line3
line4
and if you want to append to the existing...
replace(my_file, /^line2/mi) do |match|
"#{match} Some nice little sentence"
end
line1
line2 Some nice little sentence
line2
line3
line4
A couple other options:
file = File.read(path).sub(/line2\n/, 'Some nice little sentence\n\1')
File.write(path, file)
file = File.readlines(path)
index = file.index("line2")
file.insert(index, "Some nice little sentence")
File.write(path, file)
The easiest way is to read the whole file in memory, then write the first part back to the file, write your inserted line to the file, and write the remaining part back to the file. This should be relatively simple to do when you read the file as an array of lines, but you might run into problems if your file is very large since you have to read the entire file into memory with this approach.
Alternatively you could find the spot that you want to insert the line, read the lines after that point into memory, seek back to that point in the file, write your new line to the file, and finally write the remaining lines to the file. Again you'll run into problems if the remainder of the file is very large since you have to read it all into memory.
A third approach is to write the first part into a new file, write the inserted line into a new file, write the remainder of the original file into the new file, and finally replace the old file with the new file on the file system. This approach allows you to deal with one line at a time so you can handle files that do not fit into memory.
The reason why file writing works like this is because the file is like a fixed size array of bytes: when you write a byte to the file you will overwrite an existing byte (I'm ignoring the case where you append to a file here). So the only way to insert anything to a file is to first move the old content to a new location by reading it from the old location and writing it to the new location. After that you can 'insert' data into the now vacant area.
The tty-file gem has an inject_into_file method for this purpose.
Install the gem:
gem install tty-file
Then:
require 'tty-file'
TTY::File.inject_into_file("filename.rb", "Some nice little sentence", after: "line1\n")

Resources