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

File API w/ Seek/Flush - Now has (working) binary file support!

Started by KillaVanilla, 09 November 2012 - 10:23 AM
KillaVanilla #1
Posted 09 November 2012 - 11:23 AM
Hello all.

Introduction:

I've been using CC for a while, and it bothered me that there are is no seek function in the FS API.
In other words, you either overwrite the whole entire file, or append to it; you can't place text inside of previously existing text.

However, with this API you can.

This API makes file handles that are similar in use to the file handles produced by the io API, but with added functions: seek, update, and flush. In addition, all you need to open a file with this API is a filename; there are no modes. Unfortunately, this means that binary mode is not supported yet. I'm working on it!

How to Use:

API Functions:
  • open(filename) - Opens a file in text mode.
  • openBinary(filename) - Opens a file in binary mode.
All file handle functions require the self parameter:


myfile.write("data") -- wrong, don't use periods
myfile:write("data") -- right, do use colons

Text-Mode File Handle Functions:
  • writeToBuffer(data) - Internal, used by write().
  • update() - Updates the internal buffer with what's on the hard drive.
  • seek(whence, offset) - Sets where characters will be read/written.
  • flush() - Writes the buffer to disk.
  • write(…) - Writes all passed arguments to the buffer.
  • clear() - Sets the interal buffer to the empty string.
  • writeLine(…) - Writes all passed arguments to the buffer with newlines appended.
  • readLine() - Reads until it finds a newline.
  • readAll() - Reads all characters from the current position to the end of the file
  • read(chars) - Reads chars characters from the file.
  • lines() - Iterates over every line in the file.
  • autoSeek(mode) - sets the autoseek mode.
Binary-Mode File Handle Functions:
  • readAll() - Returns a table with every byte in the file
  • read(bytes) - Returns a table with bytes bytes from the file.
  • write(…) - Writes all passed arguments to the buffer.
  • flush() - Writes the buffer to disk.
  • clear() - Sets the buffer to the empty table.
  • update() - Sets the buffer to what's on the hard drive.
  • bytes() - Returns an iterator that loops over every byte in the buffer.
  • autoSeek(mode) - Sets the autoseek mode.
How to use seek():
seek() takes two arguments: whence and offset.
whence is where to seek from.
offset is how many bytes/characters to move the position up/down.
When seek() is used, it will return the new position of the seek pointer.

Example:


handle:seek("cur", 5) -- moves the seek pointer 5 characters/bytes up
handle:seek("cur", -5) -- moves the seek pointer 5 characters/bytes back
handle:seel("set") -- returns the seek pointer to the start of the file
handle:seek("cur") -- returns where the seek pointer is
handle:seek("end") -- returns the length of the file

How to use autoSeek():
autoSeek() takes one argument: mode.
The mode determines when the API will use "auto-seeking":
  • Passing no mode at all, or passing "n", will disable "auto-seeking". This is the default behavior.
  • Passing "r" will activate automatic seeking for reads only.
  • Passing "w" will activate automatic seeking for writes only.
  • Passing "rw" will activate automatic seeking for both reads and writes.
To show how this affects reading/writing, here's an example:

With autoseek off:

handle:write("a", "b", "c")
handle:flush()

produces this:


cba

However, with autoseek on:

handle:write("a", "b", "c")
handle:flush()

produces the expected:


abc

As for reading from files, what happens is obvious.
If you read with autoseek off, you will read the text from the same position every time:

-- Assuming the handle points to a file with "Test File" inside of it:
handle:read(4) -- returns "Test"
handle:read(9) -- returns "Test File"
handle:read(3) -- returns "Tes"

handle:readAll() -- returns "Test File"
handle:readAll() -- returns "Test File" again


Download:
File API w/ Seek on Pastebin

or alternatively, download the API in-game with this:

pastebin get a2yes8pR [APIName]
Cranium #2
Posted 09 November 2012 - 01:08 PM
I really like this idea. Good job on doing this! I see others would like to use it.
CoolisTheName007 #3
Posted 12 November 2012 - 10:49 AM
I will be using this for efficient editing of large blueprints stored in 3D arrays.
Thanks!!!
Although using a class for creating file objects would avoid creating new functions each time a file is created.
Sebra #4
Posted 19 November 2012 - 04:00 AM
Sorry, but I do not like it.
Mixing modes, inobvious default behavior … No.
KillaVanilla #5
Posted 19 November 2012 - 01:08 PM
I will be using this for efficient editing of large blueprints stored in 3D arrays.
Thanks!!!
Although using a class for creating file objects would avoid creating new functions each time a file is created.

I'm glad you like it, and about the file objects: I'm not new to lua, but I'm not an expert. I had no idea that lua even had the concept of classes, just tables.

Sorry, but I do not like it.
Mixing modes, inobvious default behavior … No.

The "inobvious default behavior" is easily remedied.

EDIT: and now it's fixed. It only took the changing of 4 default settings from true to false.
CoolisTheName007 #6
Posted 20 November 2012 - 08:49 AM
I will be using this for efficient editing of large blueprints stored in 3D arrays.
Thanks!!!
Although using a class for creating file objects would avoid creating new functions each time a file is created.

I'm glad you like it, and about the file objects: I'm not new to lua, but I'm not an expert. I had no idea that lua even had the concept of classes, just tables.

Classes are more of a construction of tables and metatables, which I can explain in a nutshell:

>a={5,7}
table...
>a.n
nil
>setmetatable(a,{__index={n=3})
table...
>a.n
3
>for i,v in pairs(a) do print(i,v) end
15
27
Confused? Metatables can be used to set metamethods, i.e. variables that alter the default behavior of tables in Lua. The __index metamethod can be a table; whenever a[k] would normally return nil, Lua returns __index[k]. That can be used to spare some memory while structuring classes; there's also the trick of using object:function() instead of function(object):



--define class functions...
--another trick: if a is a table
function a.foo(s)
  print(s)
end
--a:foo() is the same as calling a.foo(a)
--defining functions in the same way:
function a:foo()
  print(self)
end
--the table a, which was used to store the function, now is always a hidden first argument named self when calling foo, ie.:
a:foo()-->table
a.foo(1)--> 1 (self is 1)

--combining:
myClass={}
myClass.__index=myClass

myClass.new(field)
  local object={}
  setmetatable(object,myClass)
  object.field=field
  return object
end

myClass:mymethod()
  print(self.field)
end

obj=myClass.new(3)
obj:mymethod() --prints 3


You can check out more at http://www.lua.org/pil/16.html
Eventually, you would like to do something like obj=myClass(), and that can be done by using another metamethod, __call. For a 30 lines implementation of general classes, see https://github.com/Yonaba/30log .
KillaVanilla #7
Posted 21 November 2012 - 05:00 PM
-snip-

I know what classes are; I just didn't know Lua had them. As a matter of fact, C++ was the first language I've ever learned. (*cough* make EVERYTHING an abstract base class! *cough*)

Thanks for the link to the tutorial, though. Now, I'm going to rewrite this API to make use of this.

EDIT: Aaaand done.
CoolisTheName007 #8
Posted 21 November 2012 - 11:16 PM
-snip-

My god, C++ as first language, you got balls. Btw, if you ever want to use inheritance, the link I gave won't work too well; there are several improvements, you can search if you want.
KillaVanilla #9
Posted 22 November 2012 - 01:48 PM
-snip-

My god, C++ as first language, you got balls. Btw, if you ever want to use inheritance, the link I gave won't work too well; there are several improvements, you can search if you want.

It's fine for this implementation; I'm not using inheritance and don't plan on doing so. Still, thanks for the heads-up.
crackroach #10
Posted 05 December 2012 - 10:02 AM
how do I use the link for an in-game download??
Espen #11
Posted 05 December 2012 - 10:34 AM
how do I use the link for an in-game download??
Look again, it says how right below the download link. ;)/>
crackroach #12
Posted 05 December 2012 - 12:07 PM
how do I use the link for an in-game download??
Look again, it says how right below the download link. ;)/>

It is as simple as that, really?

I thought it was to easy to be easy. :lol:/>
Espen #13
Posted 05 December 2012 - 07:31 PM
It is as simple as that, really?

I thought it was to easy to be easy. :lol:/>
Well, the ComputerCraft server you're on would have to have HTTP API enabled for this to work.
But aside from that, yeah it's that simple. Fortunately not everything is too good to be true, hehe.^^