I want to read a specific line in lua. I have the following piece of code, but it's not working according to my needs, can anybody help?
#!/usr/bin/env lua
local contents = ""
local file = io.open("IMEI.msg", "r" )
if (file) then
-- read all contents of file into a string
contents = file:read()
file:close()
print(contents)
specific = textutils.unserialize(contents)
print(specific[2])
else
print("file not found")
end
If you just need to read one line, creating a table of all lines is unnecessary. This function returns the line without creating a table:
function get_line(filename, line_number)
local i = 0
for line in io.lines(filename) do
i = i + 1
if i == line_number then
return line
end
end
return nil -- line not found
end
You can use io.lines for this. io.lines returns an iterator over the lines in the file. If you want to access a specific line, you will first have to load all the lines into a table.
Here's a function that pulls the lines of a file into a table and returns it:
function get_lines(filename)
local lines = {}
-- io.lines returns an iterator, so we need to manually unpack it into an array
for line in io.lines(filename) do
lines[#lines+1] = line
end
return lines
end
You can index into the returned table to get the specified line.
Related
Just wondering about that, because i don't find a solution for it. Pretty sure because I'm new to this c: Thanks for your help.
Edit: for explanation im gonna explain it with the code a bit.
local FileList = fs.list("") --Makes a Table with all the files and directories available (as strings) on the PC it's running on (Inside of a mod called computercraft for minecraft)
for _, file in ipairs(FileList) do
--Here I need a function which assigns every string from the table to a variable, just for the explanation I'll call it unknown.function
unknown.function
end
while true do
print(a) --a is for example one of the different variables made from the "unknown.function"
sleep(1)
end
LIKE this?
AllFiles = {}
function Crazyfunction(file)
AllFiles[table.getn(AllFiles)+1] = file
end
local FileList = fs.list("")
for _, file in ipairs(FileList) do
Crazyfunction(file)
end
while true do
print(AllFiles[NUMBE_OF_FILE_HERE])
sleep(1)
end
You mean like this?
local FileList = fs.list("")
for _, file in ipairs(FileList) do
-- file is the variable which contains a string from the table.
print(file)
sleep(1)
end
What you want is... already what your loop does. You just added an extra loop for no reason.
I'm currently working on a logging system. My problems arise when using for loops and file writing. Here is a small example:
file = io.open("text.txt","a") --text.txt can be literally anything
for i=1,8 do
if x == true then
file:write("X is true.")
elseif y == true then
file:write("Y is true.")
end
end
Is there a way to stop the file from being written to multiple times without using file:close()? I have a huge number of different file:write sections, and adding file:close() after all of them would be a massive problem.
If file:close() every time is a massive problem, then this is the custom logic you need.
myFileMetatable = {} --implement all necessary file operations here
function myFileMetatable.write(self, str)
if not self.written then
self.written = true
self.f:write(str)
end
end
function myFileMetatable.close(self)
self.f:close()
end
myFile = {}
function myFile.open(filename, mode)
local t = {f = io.open(filename, mode)}
setmetatable(t, {__index = myFileMetatable})
return t
end
--now you can do
file = myFile.open("test", "w")
file:write("test")
file:write("hello")
file:write("world")
file:close() --and only "test" will be written
Note that this is probably much better than replacing file:write(str) with something file_write(file, str), since you need to store somewhere the fact that the file has already been written to, which you cannot store inside the FILE* object and using a global variable for that will break when using multiple files. That's why I wrap the FILE* object in a table and use myFileMetatable to implement my own methods that I will need.
However, if you need just one file at a time and don't mind the global variable then this is more efficient.
file_written = false
function file_write(file, str)
if not file_written then
file_written = true
file:write(str)
end
end
file = io.open("test", "w")
file_write(file, "test")
file_write(file, "hello")
file_write(file, "world")
file:close()
Mind that it's not as pretty as the first example and you might face a problem in the future, if you decide to expand beyond one file.
How Egor Skriptunoff already said, I'll recommend you to write your own writing function. I'm normally using sth. like this:
local function writeFile(filePath, str)
local outfile = io.open(filePath, 'w')
outfile:write(str)
outfile:close()
end
For appending to the file easily change the mode from w to a.
For my specific case, I've found a solution - since I just want a single option to print, and it's the last option (rather than the first, and I should've specified this), I can just set a variable to what I want my output to be and write that at the end.
log = ""
if x == 2 then
log = "X is 2."
elseif y == 2 then
log = "Y is 2."
end
file:write(log)
For the last option, I'd refer anyone to the accepted answer which should be perfect.
I'm trying to edit a specific line in a file using lua.
For example, I have a file with 12 lines. I want to edit the 2nd line ONLY.
Line 1: Hello
Line 2: Hello again
The output file would be for example
Line 1: Hello
Line 2: Whatever
but without caring what's the content of the 2nd line. Just by the number of the line.
I figured it out after all. Here's the code:
function Initialize()
inputFile = 'PathToFile'
end
function Edit()
local file = io.open(inputFile, 'r')
local fileContent = {}
for line in file:lines() do
table.insert (fileContent, line)
end
io.close(file)
fileContent[3] = 'This line has been edited'
file = io.open(inputFile, 'w')
for index, value in ipairs(fileContent) do
file:write(value..'\n')
end
io.close(file)
end
I am searching for the easiest way to read a string which is located in a file with a variable number of lines behind:
UserName=herecomesthestring
I thought about hardcoding a the linenumber, but this won't work, because in this file, the UserName can be more then once and the line numbers aren't the same (from user to user they may change).
Read the file line-by-line
Match the line and extract the username
Put it in a list
function getusers(file)
local list, close = {}
if type(file) == "string" then
file, close = io.open(file, "r"), true
end
for line in file:lines() do
local user, value = line:match "^([^=]+)=([^\n]*)$"
if user then -- Dropping mal-formed lines
table.insert(list, user)
list[user] = value -- Might be of interest too, so saving it
end
end
if close then
file:close()
end
return list
end
Call with either a file or a filename.
I edited the function above a bit, now it works more or less, just need to edit the RegEx.
function getusers(file)
local list, close = {}
local user, value = string.match(file,"(UserName=)(.*)")
print(value)
f:close()
end
i have a webserver (uhttpd) that uses CGI with LUA.
I made a form with a textarea.
What i need is saving the content of the textarea on a file located in /etc/list.txt
I think that the LUA script have to read the POST variables, and then save them into a local file /etc/list.txt.
I already have the script for reading the file:
function file_exists(file)
local f = io.open(file, "rb")
if f then f:close() end
return f ~= nil
end
function lines_from(file)
if not file_exists(file) then return {} end
lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end
local file = '/etc/list.txt'
local lines = lines_from(file)
print ('<textarea name="mensaje" cols="40" rows="40">')
for k,v in pairs(lines) do
print(v)
end
print ("</textarea>")
This script shows me the content of file.txt onto the textarea.
Now i need a button "Save" that POST the textarea again into the file.
Thank you for your help and have a good day.
Small critique: lines_from files is overwriting a global variable lines every time it is called. That should be made local. Also opening and closing the file to see if it exists before reading it is wasteful. That operation can be folded into lines_from:
function lines_from(filename)
local lines = {}
local file = io.open(filename)
if file then
for line in file:lines(file) do
lines[#lines + 1] = line
end
file:close();
end
return lines
end
In your case there's no reason to even read the text as lines. Just read all the file's text:
function text_from(filename)
local text = ''
local file = io.open(filename)
if file then
text = file:read('*a')
file:close();
end
return text
end
local file = 'test.lua'
local text = text_from(file)
print ('<textarea name="mensaje" cols="40" rows="40">')
print(text)
print ("</textarea>")
To write the text back to the file, just reverse the procedure, opening the file in "w+" mode (replace existing data):
function save_text_to(filename, text)
local file = io.open(filename, 'w+')
if file then
text = file:write(text);
file:close();
end
end
save_text_to('foo', text)