File transfer with FTP in Lua using LuaSocket

Learn how to implement file transfers with FTP in Lua using the LuaSocket library. This guide provides practical examples and best practices for automating FTP file transfers in your Lua projects.
Security considerations
Warning: FTP transfers data in plaintext and does not provide encryption for sensitive information.
If security is a concern, consider using alternative methods such as leveraging secure system tools
like curl
or taking advantage of HTTP/HTTPS protocols when available.
Setting up LuaSocket
First, install Lua and the required dependencies:
# Install Lua and required build dependencies
sudo apt-get install lua5.4 luarocks build-essential
# Install LuaSocket
sudo luarocks install luasocket
Connecting to an FTP server
Here's how to establish a connection to an FTP server using LuaSocket:
local socket = require('socket')
local ftp = require('socket.ftp')
local ltn12 = require('ltn12')
local function connect_ftp(host, user, password, port)
local connection = {
host = host,
user = user,
password = password,
port = port or 21
}
-- Test connection
local ok, err = ftp.get({
host = connection.host,
user = connection.user,
password = connection.password,
path = '/'
})
if not ok then
return nil, 'Failed to connect: ' .. (err or '')
end
return connection
end
Listing files and directories
This function retrieves and parses directory listings from the FTP server:
local function list_directory(connection, path)
local t = {}
local ok, err = ftp.get({
host = connection.host,
user = connection.user,
password = connection.password,
path = path,
type = 'a',
sink = ltn12.sink.table(t)
})
if not ok then
return nil, 'Failed to list directory: ' .. (err or '')
end
local listing = table.concat(t)
local files = {}
for filename in listing:gmatch('([^\r\n]+)') do
if filename ~= '.' and filename ~= '..' then
table.insert(files, filename)
end
end
return files
end
Downloading files from the FTP server
Implement secure file downloads with proper error handling:
local function download_file(connection, remote_path, local_path)
local file, err = io.open(local_path, 'wb')
if not file then
return nil, 'Failed to open local file: ' .. (err or '')
end
local ok, err = ftp.get({
host = connection.host,
user = connection.user,
password = connection.password,
path = remote_path,
sink = ltn12.sink.file(file),
type = 'i' -- binary transfer
})
file:close()
if not ok then
os.remove(local_path) -- Clean up failed download
return nil, 'Failed to download file: ' .. (err or '')
end
return true
end
Automating FTP file imports
Here's a complete example that combines the above functions to automate file imports:
local function import_files(connection, remote_dir, local_dir)
-- Create local directory if it doesn't exist
local ok, err = os.execute('mkdir -p ' .. local_dir)
if not ok then
return nil, 'Failed to create local directory: ' .. (err or '')
end
-- List remote files
local files, err = list_directory(connection, remote_dir)
if not files then
return nil, err
end
-- Download each file
local results = {}
for _, file in ipairs(files) do
local remote_path = remote_dir .. '/' .. file
local local_path = local_dir .. '/' .. file
local ok, err = download_file(connection, remote_path, local_path)
results[file] = {
success = ok ~= nil,
error = err
}
end
return results
end
Error handling and best practices
Implement a robust error handling wrapper for FTP operations:
local function with_ftp_connection(host, user, password, callback)
local connection, err = connect_ftp(host, user, password)
if not connection then
return nil, err
end
local ok, result = pcall(callback, connection)
if not ok then
return nil, 'Operation failed: ' .. tostring(result)
end
return result
end
-- Usage example
local results = with_ftp_connection('ftp.example.com', 'user', 'pass', function(conn)
return import_files(conn, '/remote/dir', 'local/dir')
end)
Alternative approaches for secure transfers
Since FTP does not encrypt data, consider these alternatives if security is a concern:
- Use system commands with Lua's os.execute to invoke secure tools like curl:
local function secure_download(url, output_file)
local cmd = string.format("curl -fsSL --retry 3 '%s' -o '%s'", url, output_file)
return os.execute(cmd)
end
- Leverage HTTP/HTTPS transfers with LuaSocket, if supported by your server.
Conclusion
LuaSocket provides a straightforward way to implement FTP file transfers in Lua. Be mindful that FTP transmits data without encryption, so for sensitive data, consider secure alternatives where possible. The examples above demonstrate proper error handling and best practices to ensure reliable file transfers.
For advanced file processing needs, consider using Transloadit's encoding REST API, which offers secure file transfers and powerful processing capabilities.