1

I am learning Lua with youtube video and it introduces a way to write a text file like this:

io.output("myfile.txt")
print("My name is David") -- This won't write into the file, just print to the console
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.close()

Then it introduces a way to read text file like this:

io.input("myfile.txt")
print(io.read("*all"))
io.close()

These two code blocks works when they are in the separate lua files. However, when I combine these two code blocks into a single lua file. It generates an error.

The combined file looks like this:

-- Write file and close it
io.output("myfile.txt")
print("My name is David") -- This won't write into the file, just print to the console
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.close()

-- Read file and close it
io.input("myfile.txt")
print(io.read("*all"))
io.close()

and it shows an error when i run this file:

lua54: file.lua:36: attempt to use a closed file
stack traceback:
        [C]: in function 'io.close'
        file.lua:36: in main chunk
        [C]: in ?

The output that I expect is:

My name is David
hello world, how are you
hello world, how are you
hello world, how are you
hello world, how are you

In the meantime I also tried to delete the first io.close() so the code looks like this:

-- Write file and close it
io.output("myfile.txt")
print("My name is David") -- This won't write into the file, just print to the console
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")

-- Read file and close it
io.input("myfile.txt")
print(io.read("*all"))
io.close()

But the console output only shows the print() statement:

My name is David

I also tried to keep the first io.close() and delete second io.close(). I got the expected output.

The code looks like this:

-- Write file and close it
io.output("myfile.txt")
print("My name is David") -- This won't write into the file, just print to the console
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.write("hello world, how are you\n")
io.close()

-- Read file and close it
io.input("myfile.txt")
print(io.read("*all"))

Output:

My name is David
hello world, how are you
hello world, how are you
hello world, how are you
hello world, how are you

Could anyone explain why there is an error and what do these codes do, Thanks!

yzrtt22
  • 13
  • 3

2 Answers2

1

io.close() closes the default output file.
To close the default input file, use io.close(io.input())

ESkri
  • 1,461
  • 1
  • 1
  • 8
  • Thanks for your help! I am still confused with the code which I closed default output file after `io.input()` (This is the code that I mentioned above with output `My name is David` only) because this is not the output that I expected. Could you give me explanation, please – yzrtt22 Jun 22 '23 at 15:33
  • You have not flushed the file buffers, so the content you have written (to the buffer) never stored to the file. Closing the file automatically flushes the buffers. – ESkri Jun 22 '23 at 17:39
  • `io.close(io.input())` (or the variant `io.stdin:close()`) both return `nil, "cannot close standard file"` for me on Lua 5.4. – Luatic Jun 22 '23 at 19:09
  • @Luatic - Only redefined input file could be closed. You can not close STDIN. – ESkri Jun 23 '23 at 08:26
0

More important than io.close() is io.flush() in your case.
Example (typed in Lua 5.1 Standalone)

$ readline-editor lua5.1
Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> io.output("myfile.txt")
> io.write("Line 1\n")
> io.write("Line 2\n")
> io.write("Line 3\n")
> io.write("Line 4")
> io.flush() -- This writes the Buffered Text into the File (finally)
> -- io.flush() even has to be used if Text
> -- (or Chars) outputted slowly within a loop
> -- and a sleep() or wait() is used
> -- Example:
> -- do local txt = "Hey"
> -- for i = 1, #txt do
> --   io.write(txt:sub(i, i))
> --   io.flush() -- Necessary before a sleep() or wait()
> --   sleep(0.25)
> -- end
> -- io.write('\n')
> -- end
> print("My Name Is Lx")
My Name Is Lx
> return(io.open("myfile.txt"):read("*a"))
Line 1
Line 2
Line 3
Line 4
> print(io.open("myfile.txt"):read("*a"))
Line 1
Line 2
Line 3
Line 4
> io.output(io.stdout)
> io.write(io.open("myfile.txt"):read("*a"))
Line 1
Line 2
Line 3
Line 4> 

For me the best Method to close probably unkown and open File Handle' are...

collectgarbage("collect")

Because the Datatype userdata has a MetaMethod __gc that closes such free unknown Zombies
Example

> io.open("myfile.txt", "w"):write(("Used by Lua: %d\n"):format(collectgarbage("count")))
> io.write(io.open("myfile.txt"):read("*a")) -- Nothing
> io.write(io.open("myfile.txt"):read("*a")) -- Nothing
> collectgarbage("collect") -- Flush & Close open File Handle
> io.write(io.open("myfile.txt"):read("*a"))
Used by Lua: 18

file:close ()
Closes file. Note that files are automatically closed when their handles are garbage collected, but that takes an unpredictable amount of time to happen.
Reference: https://www.lua.org/manual/5.1/manual.html#5.7

PS: The Garbage Collector can be tuned and this can also be interest for embedded WiFi IoT Device Developer which always have to little Memory for Lua
So check out this...

> collectgarbage("setpause", 8)
> collectgarbage("restart")
> io.open("myfile.txt", "w"):write(("%s Bytes used by Lua: %.f\n"):format(os.date("[%T]"), collectgarbage("count") * 1024))
> io.write(io.open("myfile.txt"):read("*a"))
[23:51:55] Bytes used by Lua: 18244
> io.open("myfile.txt", "w"):write(("%s Bytes used by Lua: %.f\n"):format(os.date("[%T]"), collectgarbage("count") * 1024))
> io.write(io.open("myfile.txt"):read("*a"))
[23:52:11] Bytes used by Lua: 18244
> return(("%s Bytes used by Lua: %.f\n"):format(os.date("[%T]"), collectgarbage("count") * 1024))
[23:52:32] Bytes used by Lua: 18065

> return(("%s Bytes used by Lua: %.f\n"):format(os.date("[%T]"), collectgarbage("count") * 1024))
[23:52:40] Bytes used by Lua: 18041

> return(("%s Bytes used by Lua: %.f\n"):format(os.date("[%T]"), collectgarbage("count") * 1024))
[23:52:42] Bytes used by Lua: 18041

> return(("%s Bytes used by Lua: %.f\n"):format(os.date("[%T]"), collectgarbage("count") * 1024))
[23:52:44] Bytes used by Lua: 18041
koyaanisqatsi
  • 2,585
  • 2
  • 8
  • 15