This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Commader_Fox's profile picture

fs.open problem

Started by Commader_Fox, 04 November 2014 - 01:26 PM
Commader_Fox #1
Posted 04 November 2014 - 02:26 PM
Hello,
as the title specifies, i have a problem with the fs api. I have made several test scripts to show you what i mean.
I am making an study program for people of my own language, so they can use Computercraft to start with the basics of programming. I want to make a config file for this. There is a way, where i just pin the whole config in the startup of the pc, and make it use strings for global use, but that would be unnecessary since there already is a api for that. I have been struggling with this for a long time now, and would like to know if this is an error on my side or on the Computercraft side.

What you need to know:
I never have errors while doing this. Only when i try to use the nil value for something that it ain't meant for.
Also i am fairly new in lua, i learned the whole language so far in 2 weeks. So there are some things i need to learn.
I know: for, if, when, function, variables, tables, #, events, peripheral, rednet, and the rest below this level of programming.
Also i have searched a lot for this error, but the only post i find are human errors, or things that are not dedicated to my problem.

The error:
none, literally, none. it returns a nil value every time i try to use the file.read() thing.

I did the following:

First, i copied the exact same code from some one else, which used the io api, and seemed to work just fine for him.

I made a test script (2 total, i tried io to, but that's completely new ground for me)

scripts:

For the writing i used a script called write:

local table = { 'test' } --Not needed, i know, but just for testing.
local file = fs.open('dataA', 'w')
file.write(table[1])
file.close()
local file = fs.open('dataB', 'w')
file.writeLine('Test B')
file.close()

For the reading i used a script called read:

local file = fs.open('dataA', 'r')
local table = file.readAll()
print('read all:\n', table[1])
local table = file.readLine()
print('read line:\n', table)
file.close()
local file = fs.open('dataB', 'r')
local table = file.readAll()
print('read all (B)/>:\n', table[1])
local table = file.readLine()
print('read line (B)/>:\n', table)
file.close()
print 'done'

When you use the writing script, It makes the following files:

dataA:

test

dataB:

Test B

When i use the reading script, it outputs the flowing:


>test2
read all:

read line:

read all (B)/>:

read line (B)/>:

done
>  _

As you can see it won't output a thing. I have done this with the lua command prompt on the pc yesterday, and still nothing. for readAll() it returns a table, which is empty. For the readLine, it returns a nil. This is very confusing for me, since i have no idea what's going on here. Did i make a mistake? And why won't it give me an error if that's the case?

I have the patience to wait for an answer, but it's really bugging me when i'm studying.

Greetings from the Fox.
Edited on 07 November 2014 - 05:10 PM
Lyqyd #2
Posted 04 November 2014 - 05:45 PM
This should be throwing errors. I'm not sure why it isn't.

You definitely shouldn't call your variables "table", since that will obliterate the table library. File handles are single-pass. Once you've read all of the contents, that's all there is to it, so a readLine call on a handle following a readAll call on that handle will always return nil. Try this sample code on a freshly booted computer:


local handle = fs.open("foo", "w")
if handle then
  handle.write("bar")
  handle.close()
else
  print("Couldn't open file!")
end


local handle = fs.open("foo", "r")
if handle then
  print("line", handle.readLine())
  handle.close()
else
  error("Couldn't open file!")
end

local handle = fs.open("foo", "r")
if handle then
  print("all", handle.readAll())
  handle.close()
else
  error("Couldn't open file!")
end
ElvishJerricco #3
Posted 04 November 2014 - 06:06 PM
This should be throwing errors. I'm not sure why it isn't.

readAll returns a string, and doing str[1] will just return nil due to strings' table-like behavior. The other scenarios just see readLine returning nil. So everything that he tries to print is nil, and because he's not concatenating but is instead passing these nils into print as additional arguments, print doesn't even know they were passed (because they're nil) and ignores them entirely.
Edited on 04 November 2014 - 05:07 PM
Commader_Fox #4
Posted 07 November 2014 - 03:53 PM
Sorry for the late reply,

The code you gave me was very usefull, and i have been able to make the folowing script with it:

save

remember = {
readAll = function(file)
  if fs.exists(file) then
	local handle = fs.open(file, "r")
	local data = {}
	local line = 'string'
	local i=1
	while line do
	 line = handle.readLine()
	 table.insert(data,i,line)
	 i=i+1
	end
	handle.close()
	if data[1] == nil then data = nil end
	return(data)
  end
end,

writeAll = function(file, val)
  local backup = remember.readAll(file)
  local handle = fs.open(file, 'w')
  if type(val) == 'string' then
	handle.writeLine(val)
  elseif type(val) == 'table' then
	for i=1,#val do
	  handle.writeLine(val[i])
	end
  else
	print('Oops, you suposed to give me an string or table\nyou silly, not a ',type(val))
  end
  handle.close()
  return(backup)
end,

readLine = function(file, line)
  if type(file) == 'string' then
	if tonumber(line) then
	  local data = remember.readAll(file)
	  return(data[line])
	else
	  print('Oops, you\'re supposed to give an number\nhere, not an ',type(line))
	end
  else
	print('Oops, it looks like you gave a ',type(file),' as an \nfile name. Try using a string.')
  end
end,

writeLine = function(file, line, txt)
  if type(line) == 'number' then
	if txt then
	  local data = remember.readAll(file)
	  if data == nil then
		data = {}
		for i = 1,line do
		  if data[i] == nil then
			data[i] = ""
		  end
		end
	  elseif data[line] then
		backup = data[line]
	  end
	  data[line] = txt
	  remember.writeAll(file,data)
	  return(backup)
	else
	  print('Error: expected string or table.\nGot ',type(txt))
	end
  else
	print('Error: expected number, got ', type(line))
  end
end }

This is very useful for my lessons for those who want to learn Lua! So thanks a ton, i will be sure to ask again if i need help again.

Also i wan't to say thanks to ElvishJerricco for explaining why it gave no errors. I used this for analyzing the string it gave me. Although i have been unable to convert this to a table (with textutils or string) but since i have no experience on that area yet, its understandable it failed. but i will surely return to this later on.

One quick question though,
i see many of you use the same names for variables and files for testing like "foo" and "handle".
So what names do you use for Tables? And are there more to know?

Anyhow, thanks again, and i will keep in mind not overwriting imported tables.

Greetings from the Fox
Lyqyd #5
Posted 07 November 2014 - 05:14 PM
Well, foo, bar and baz are commonly used as example variables/filenames/etc., and I tend to use "handle" for any file handles I open. You can call your variables anything you want, I'd just suggest not calling them table (or math, or string, or fs, etc.), since those names are used for libraries and APIs, and you don't want to overwrite them.
KingofGamesYami #6
Posted 07 November 2014 - 06:20 PM
When defining variables, I'll sometimes put a letter representing the type in front of it, like this:

local tArgs = {} --#table of arguments
local sSide = "right" --#string side
local bFlip = true --#boolean variable
local nScore = 1 --#number score

If I need any table, I'll name the variable in my function

function foo( tbl )
end

if I need any string, I'll name the variable in my function

function foo( str )


However, you are free to do as you like. I dislike people that use non-descriptive variables, as it makes it hard to read their code.
Commader_Fox #7
Posted 07 November 2014 - 08:29 PM
Thanks, a lot.

Those both look very nice, really, and very efficient. The bar and baz look new to me, i can't help but wonder how someone thinks of those names. and by combining them with the types like n and s, they cold become very clear.

Thanks allot. Both of you, i am really bad with thinking of names, so this helps me quite allot.

Since you all have been such a help to me, i wonder if you could answer this one last question for me. It's not really lua related, but it has something to do with my study.
Anyway, i have placed it in a spoiler so answer it if you like.
Question (off-topic)Since i am learning lua all by my self, i tend to… overdo it. The thing is though, this gives me kind of a burnout, what results in me, not being able to program for days, it also makes me distracted all the time. I know this is probably from just programming to much. So, does this ever happen to any of you out there? And what do you do when it happens, or even more imported, how do you prevent it without sacrificing programming time?

Thanks for all the help, and i think next time you see a script of mine, you will find some nBar's and tFoo's in there. Not to forget str and tbl's.

Greetings from the Fox.
Edited on 07 November 2014 - 07:57 PM
Bomb Bloke #8
Posted 07 November 2014 - 11:26 PM
I'm the other way around; the less programming I do, the less I want to program. The more programming I do, the more I want to program. If I make myself sit down and start something, I'll generally have no problems finishing it.

In terms of concentration, I find music helps greatly, occupying a part of my mind that otherwise gets bored. In particular, ambient music - anything lyrical or overly bombastic chews up too much of my attention. Background music from strategy games is quite ideal; try this on for size.
Commader_Fox #9
Posted 08 November 2014 - 04:07 PM
I'm the other way around; the less programming I do, the less I want to program. The more programming I do, the more I want to program. If I make myself sit down and start something, I'll generally have no problems finishing it.

In terms of concentration, I find music helps greatly, occupying a part of my mind that otherwise gets bored. In particular, ambient music - anything lyrical or overly bombastic chews up too much of my attention. Background music from strategy games is quite ideal; try this on for size.
Thanks yet again, This form amazes me a lot actually, the hospitality level is pretty high here.
I will make sure i listen to some chillstep next time i program a big code. I'm thinking of making a table where everything inside is a profile specified for the device connected. So i can just do something like: devices.monitor.one.write('test')

A burnout is not particularly useful in that case, so thanks for the tip. I must say though, i did this the other day, and i did notice the difference. I should have gotten the hint back then.

Anyways, i'm going to program this weekend, so thanks for the tip.

PS: I did play that music from the link you gave me, did you try enabling the Scoop visualization in WMP? It's so weird.

See you on the next bug,
Greetings from the Fox.