File I/O Functions
Overview
This module provides sandboxed file operations for reading and writing data. The scripting environment is intentionally sandboxed to prevent malicious code from accessing arbitrary files on your system.
You can interact with files in two allowed locations:
- Game Files - Inside the World of Warcraft installation folder (read-only)
- Loader Data Files - Inside the loader's
scripts_data/folder (read/write)
For simple logging needs, we recommend using izi.log from the izi library. It handles file creation and management automatically, making it much faster than manually building log files.
Game Files (Read-Only) 📖
These functions allow you to read files from inside the World of Warcraft installation folder. Any path outside the WoW folder is blocked.
core.read_file
Syntax
core.read_file(filename: string) -> string
Parameters
filename:string- Path inside the World of Warcraft folder (UTF-8).
string: The file contents as a Lua string. Returns empty string or nil on failure.
Reads the entire contents of a sandboxed game file. Use relative-style paths such as Data/... or _retail_/... depending on your client layout.
Example Usage
local text = core.read_file("_retail_/WTF/Config.wtf")
if text and #text > 0 then
core.log("Config length: " .. #text)
end
core.read_file_partial
Syntax
core.read_file_partial(filename: string, offset: integer, size_to_read: integer) -> string|nil
Parameters
filename:string- Path inside the World of Warcraft folder (UTF-8).offset:integer- Byte offset to start reading from.size_to_read:integer- Number of bytes to read.
string|nil: The read bytes as a Lua string, or nil on failure.
Reads a portion of a sandboxed game file, starting at a byte offset. The returned string can contain binary data and may include zero bytes.
Example Usage
local path = "_retail_/WTF/Config.wtf"
local chunk = core.read_file_partial(path, 0, 64)
if chunk then
core.log("First 64 bytes: " .. chunk)
else
core.log("Read failed (outside sandbox, missing, or access denied)")
end
core.get_file_size
Syntax
core.get_file_size(filename: string) -> integer
Parameters
filename:string- Path inside the World of Warcraft folder (UTF-8).
integer: The file size in bytes. Returns 0 if file doesn't exist or isn't accessible.
Gets the size of a sandboxed game file in bytes.
If you need to distinguish between "missing" vs "empty file", attempt a small read as well.
Example Usage
local path = "_retail_/WTF/Config.wtf"
local size = core.get_file_size(path)
if size > 0 then
core.log("Config size: " .. size .. " bytes")
else
core.log("Missing, blocked, or empty file")
end
Loader Data Files (Read/Write) 💾
These functions allow you to read and write files inside the loader's scripts_data/ directory. This is the only directory writable by scripts.
Important: All paths are relative to scripts_data/. Do not prefix with scripts_data/ yourself.
core.create_data_folder
Syntax
core.create_data_folder(folder: string) -> nil
Parameters
folder:string- Folder path insidescripts_data/(UTF-8).
Creates a folder inside the loader's scripts_data/ directory.
Example Usage
-- Creates: <loader_path>/scripts_data/profiles/
core.create_data_folder("profiles")
-- Then you can create files in it
core.create_data_file("profiles/user1.json")
core.create_data_file
Syntax
core.create_data_file(filename: string) -> nil
Parameters
filename:string- Path insidescripts_data/(UTF-8).
Creates a new data file inside the loader's scripts_data/ directory. Parent folders should exist - use core.create_data_folder for subfolders if needed.
Example Usage
core.create_data_file("settings.json")
core.write_data_file("settings.json", "{}")
core.write_data_file
Syntax
core.write_data_file(filename: string, data: string) -> nil
Parameters
filename:string- Path insidescripts_data/(UTF-8).data:string- The data to write into the file.
Writes data to a loader data file inside scripts_data/. In most systems, this overwrites the file.
Example Usage
core.write_data_file("cache/state.txt", "last_login=123")
core.read_data_file
Syntax
core.read_data_file(filename: string) -> string
Parameters
filename:string- Path insidescripts_data/(UTF-8).
string: The file contents as a Lua string.
Reads the entire contents of a loader data file from scripts_data/. The returned string can contain binary data.
Example Usage
local json = core.read_data_file("settings.json")
if json and #json > 0 then
core.log("Settings: " .. json)
end
core.read_data_file_partial
Syntax
core.read_data_file_partial(filename: string, offset: integer, size_to_read: integer) -> string|nil
Parameters
filename:string- Path insidescripts_data/(UTF-8).offset:integer- Byte offset to start reading from.size_to_read:integer- Number of bytes to read.
string|nil: The read bytes as a Lua string, or nil on failure.
Reads a portion of a loader data file from scripts_data/, starting at a byte offset. The returned string can contain binary data and may include zero bytes.
Example Usage
local chunk = core.read_data_file_partial("settings.json", 0, 256)
if chunk then
core.log("JSON header: " .. chunk)
else
core.log("Read failed (missing or blocked)")
end
core.get_data_file_size
Syntax
core.get_data_file_size(filename: string) -> integer
Parameters
filename:string- Path insidescripts_data/(UTF-8).
integer: The file size in bytes.
Gets the size of a loader data file in bytes from scripts_data/. Returns 0 if file doesn't exist or isn't accessible.
Example Usage
local size = core.get_data_file_size("settings.json")
if size > 0 then
core.log("settings.json size: " .. size .. " bytes")
else
core.log("Missing, blocked, or empty file")
end
core.read_dir
Syntax
core.read_dir(directory: string) -> string[]|nil
Parameters
directory:string- Directory path insidescripts_data/(UTF-8).
string[]|nil: Array of file/folder names, ornilon failure.
Lists all files and folders in a directory inside scripts_data/. Returns an array of names (not full paths). Includes both files and subdirectories but does not include . or .. entries.
This function only works within the scripts_data/ sandbox. Any path that resolves outside this directory will return nil.
Example Usage
-- List all files in the profiles folder
local files = core.read_dir("profiles")
if files then
core.log("Found " .. #files .. " items:")
for i, name in ipairs(files) do
core.log(" " .. name)
end
else
core.log("Directory not found or access denied")
end
Example: Finding All JSON Files
local function get_json_files(folder)
local files = core.read_dir(folder)
if not files then return {} end
local json_files = {}
for i = 1, #files do
local name = files[i]
if name:match("%.json$") then
table.insert(json_files, name)
end
end
return json_files
end
local configs = get_json_files("configs")
for _, filename in ipairs(configs) do
core.log("Found config: " .. filename)
end
Log Files 📝
Log files are intended for diagnostics and debugging output. The exact storage location is implementation-defined by the loader.
For quick and easy logging, consider using izi.log from the izi library instead of manually managing log files.
core.create_log_file
Syntax
core.create_log_file(filename: string) -> nil
Parameters
filename:string- The name of the log file to create.
Creates a new log file.
If the log file already exists, the native side may truncate it or keep it, depending on implementation.
core.write_log_file
Syntax
core.write_log_file(filename: string, message: string) -> nil
Parameters
filename:string- The name of the log file to write to.message:string- The message to write into the log file.
Writes a message to a log file. Use this for debug output that should persist outside the in-game console.
Whether a newline is automatically appended depends on native implementation. If you want one, include "\n" yourself.
Example Usage
-- Create a log file at startup
core.create_log_file("combat.log")
core.write_log_file("combat.log", "Addon started\n")
-- Log events during gameplay
core.write_log_file("combat.log", "Target acquired: " .. tostring(unit_name) .. "\n")
core.write_log_file("combat.log", "Spell cast: " .. spell_name .. " at " .. tostring(core.game_time()) .. "\n")
Complete Examples 📚
Example: Saving and Loading Settings
local SETTINGS_FILE = "my_addon/settings.json"
-- Save settings
local function save_settings(settings)
core.create_data_folder("my_addon")
core.create_data_file(SETTINGS_FILE)
-- Convert table to JSON string (you'd use a JSON library)
local json_str = '{"enabled": true, "threshold": 50}'
core.write_data_file(SETTINGS_FILE, json_str)
core.log("Settings saved!")
end
-- Load settings
local function load_settings()
local json_str = core.read_data_file(SETTINGS_FILE)
if json_str and #json_str > 0 then
-- Parse JSON string (you'd use a JSON library)
core.log("Loaded settings: " .. json_str)
return json_str
else
core.log("No settings found, using defaults")
return nil
end
end
Example: Debug Logging System
local DEBUG_LOG = "debug.log"
local debug_enabled = true
local function init_debug_log()
if debug_enabled then
core.create_log_file(DEBUG_LOG)
core.write_log_file(DEBUG_LOG, "=== Debug session started at " .. tostring(core.game_time()) .. " ===\n")
end
end
local function debug_log(message)
if debug_enabled then
local timestamp = string.format("[%.2f] ", core.game_time() / 1000)
core.write_log_file(DEBUG_LOG, timestamp .. message .. "\n")
end
end
-- Usage
init_debug_log()
debug_log("Player entered combat")
debug_log("Cast spell ID: 12345")
Example: Loading Local Textures
For texture and icon loading, consider using these higher-level utilities instead of raw file I/O:
- Assets Helper - Automatic texture loading with caching and ZIP pack support
- Icons Helper - WoW icon loading from Wowhead with disk caching
- IZI SDK Graphics - High-level graphics API wrapping both helpers
The example below shows raw file I/O for educational purposes, but the utilities above handle caching, error recovery, and format conversion automatically.
local my_texture_id = nil
local function load_my_texture()
if my_texture_id then return end
local bytes = core.read_data_file("icons/my_icon.png")
if not bytes or #bytes == 0 then
core.log("Missing icon: scripts_data/icons/my_icon.png")
return
end
local tex_id, width, height = core.graphics.load_texture(bytes)
if tex_id then
my_texture_id = tex_id
core.log("Texture loaded! Size: " .. width .. "x" .. height)
else
core.log("Failed to decode texture")
end
end
Security Notes 🔒
- Scripts can only read from the WoW installation folder
- Scripts can only write to the
scripts_data/folder - Any attempt to access files outside these locations will fail
- This sandboxing is intentional to prevent malicious code