Moving files around
Lua does not have very many built-in file operations. Here are the few that it does have:
- os.remove(file) – Remove a file. Returns true if the file was removed. Returns nil, plus a string describing the error, if the file was not removed. Example:
local Result, ErrorString = os.remove('foo.txt') if not Result then print(ErrorString) end
- os.rename(source, dest) – Renames and/or moves a file. Returns true if the rename/move was successful. Returns nil, plus a string describing the error, if the rename/move failed. Example:
local Result, ErrorString = os.rename('foo.txt', 'subdir/bar.txt') if not Result then print(ErrorString) end
- io.open(name, [mode]) – Opens a file, creating it if necessary, provided the ‘mode’ allows creation of the file. Returns a file handle object if the open was successful. Returns nil, plus a string describing the error, if the open was not successful. ‘mode’ is a string that is in the same format as the ‘mode’ argument to standard C function, fopen. The most common modes are:
- ‘r’ – read (the default mode). The file must exist.
- ‘w’ – write. This will create the file if necessary.
- ‘a’ – append. This will create the file if necessary.
- The file handle returned from io.open has the following operations:
- handle:close() – Closes the file. It is always a good idea to explicitly call this whenever you are done with the file.
- handle:flush() – Save any written data to the file.
- handle:lines() – Returns an iterator function which can be used to iterate over each line in the file. Example:
local File = io.open('foo.txt') for Line in File:lines() do print(Line) end
- handle:read(…) – Read from the file. By default, will read one line from the file. To read all lines, pass specify ‘*a’ as the argument. For a complete list of valid arguments, see the file:read entry in the lua reference manual.
- handle:write(…) – Writes all arguments to the file.
- See the lua reference manual for the less common operations, file:seek and file:setvbuf.
- os.execute(command) – Executes ‘command’, and returns a return code (zero for success, non-zero if an error occurred). We will see in the section below how os.execute can be used for every other file operation.
Using os.execute() for Everything Else
os.execute can be used to do pretty much anything you can imagine. But it does have one limitation – you can’t get the standard output of the command. Here is a basic wrapper of the function you can use to get around this:
-- Execute a command. -- The first return value is the output from the command -- (or nil if there was no output). -- The second is the returned status code from executing the command. -- function MyExecute(Command) -- We use os.tmpname(), a built-in Lua function, to give us a -- temporary file name. local TempFileName = os.tmpname() local Result = os.execute(Command..' > '..TempFileName..' 2>&1') local TempFile = io.open(TempFileName) if TempFile then local CommandOutput = TempFile:read('*a') TempFile:close() os.remove(TempFileName) return CommandOutput, Result else return nil, Result end end
This writes the output of the command to a temporary file, then reads the file to get the output, and deletes the temporary file. Now the example in Recursive file search can be simplified like so:
-- Does a recursive search of the directory specified -- by Root, and returns the full path of the file with -- the name File, if it is found. Returns nil otherwise. -- function findFile(Root, File) return MyExecute('dir /S /B "'..Root..'" | find "'..File..'"') end
So you can see, anything you can do from the command-line, you can do with os.execute(). Other uses include, but are not limited to:
- Copying files (using the MS ‘copy’ command, or the posix ‘cp’ command)
- Creating a directory (using the MS ‘md’ command, or the posix ‘mkdir’ command)
- Removing a directory (using the MS ‘rd’ command, or the posix ‘rmdir’ command)