Attention: Here be dragons
This is thelatest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Runtime file loading and saving
See also
SeeSaving games for information on saving and loading game progression.
Sometimes,exporting packs, patches, and mods is notideal when you want players to be able to load user-generated content in yourproject. It requires users to generate a PCK or ZIP file through the Godoteditor, which contains resources imported by Godot.
Example use cases for runtime file loading and saving include:
Loading texture packs designed for the game.
Loading user-provided audio tracks and playing them back in an in-game radio station.
Loading custom levels or 3D models that can be designed with any 3D DCC thatcan export to glTF or FBX (including glTF scenes saved by Godot at runtime).
Using user-provided fonts for menus and HUD.
Saving/loading a file format that can contain multiple files but can stilleasily be read by other applications (ZIP).
Loading files created by another game or program, or even game data files fromanother game not made with Godot.
Runtime file loading can be combined withHTTP requeststo load resources from the Internet directly.
Warning
Donot use this runtime loading approach to load resources that are partof the project, as it's less efficient and doesn't allow benefiting fromGodot's resource handling functionality (such as translation remaps). SeeImport process for details.
See also
You can see how saving and loading works in action using theRun-time File Saving and Loading (Serialization) demo project.
Plain text and binary files
Godot'sFileAccess class provides methods to access files on thefilesystem for reading and writing:
funcsave_file(content):varfile=FileAccess.open("/path/to/file.txt",FileAccess.WRITE)file.store_string(content)funcload_file():varfile=FileAccess.open("/path/to/file.txt",FileAccess.READ)varcontent=file.get_as_text()returncontent
privatevoidSaveFile(stringcontent){usingvarfile=FileAccess.Open("/Path/To/File.txt",FileAccess.ModeFlags.Write);file.StoreString(content);}privatestringLoadFile(){usingvarfile=FileAccess.Open("/Path/To/File.txt",FileAccess.ModeFlags.Read);stringcontent=file.GetAsText();returncontent;}
To handle custom binary formats (such as loading file formats not supported byGodot),FileAccess provides several methods to read/write integers,floats, strings and more. These FileAccess methods have names that start withget_ andstore_.
If you need more control over reading binary files or need to read binarystreams that are not part of a file,PackedByteArray providesseveral helper methods to decode/encode series of bytes to integers, floats,strings and more. These PackedByteArray methods have names that start withdecode_ andencode_. See alsoBinary serialization API.
Images
Image'sImage.load_from_file static methodhandles everything, from format detection based on file extension to reading thefile from disk.
If you need error handling or more control (such as changing the scale an SVG isloaded at), use one of the following methods depending on the file format:
Several image formats can also be saved by Godot at runtime using the followingmethods:
Image.save_exrorImage.save_exr_to_buffer(only available in editor builds, cannot be used in exported projects)
The methods with theto_buffer suffix save the image to a PackedByteArrayinstead of the filesystem. This is useful to send the image over the network orinto a ZIP archive without having to write it on the filesystem. This canincrease performance by reducing I/O utilization.
Note
If displaying the loaded image on a 3D surface, make sure to callImage.generate_mipmapsso that the texture doesn't look grainy when viewed at a distance.This is also useful in 2D when following instructions onreducing aliasing when downsampling.
Example of loading an image and displaying it in aTextureRect node(which requires conversion toImageTexture):
# Load an image of any format supported by Godot from the filesystem.varimage=Image.load_from_file(path)# Optionally, generate mipmaps if displaying the texture on a 3D surface# so that the texture doesn't look grainy when viewed at a distance.#image.generate_mipmaps()$TextureRect.texture=ImageTexture.create_from_image(image)# Save the loaded Image to a PNG image.image.save_png("/path/to/file.png")# Save the converted ImageTexture to a PNG image.$TextureRect.texture.get_image().save_png("/path/to/file.png")
// Load an image of any format supported by Godot from the filesystem.varimage=Image.LoadFromFile(path);// Optionally, generate mipmaps if displaying the texture on a 3D surface// so that the texture doesn't look grainy when viewed at a distance.// image.GenerateMipmaps();GetNode<TextureRect>("TextureRect").Texture=ImageTexture.CreateFromImage(image);// Save the loaded Image to a PNG image.image.SavePng("/Path/To/File.png");// Save the converted ImageTexture to a PNG image.GetNode<TextureRect>("TextureRect").Texture.GetImage().SavePng("/Path/To/File.png");
Audio/video files
Godot supports loading Ogg Vorbis, MP3, and WAV audio at runtime. Note that notallfiles with a.ogg extension are Ogg Vorbis files. Some may be Ogg Theoravideos, or contain Opus audio within an Ogg container. These files willnotload correctly as audio files in Godot.
Example of loading an Ogg Vorbis audio file in anAudioStreamPlayer node:
$AudioStreamPlayer.stream=AudioStreamOggVorbis.load_from_file(path)
GetNode<AudioStreamPlayer>("AudioStreamPlayer").Stream=AudioStreamOggVorbis.LoadFromFile(path);
Example of loading an Ogg Theora video file in aVideoStreamPlayer node:
varvideo_stream_theora=VideoStreamTheora.new()# File extension is ignored, so it is possible to load Ogg Theora videos# that have a `.ogg` extension this way.video_stream_theora.file="/path/to/file.ogv"$VideoStreamPlayer.stream=video_stream_theora# VideoStreamPlayer's Autoplay property won't work if the stream is empty# before this property is set, so call `play()` after setting `stream`.$VideoStreamPlayer.play()
varvideoStreamTheora=newVideoStreamTheora();// File extension is ignored, so it is possible to load Ogg Theora videos// that have a `.ogg` extension this way.videoStreamTheora.File="/Path/To/File.ogv";GetNode<VideoStreamPlayer>("VideoStreamPlayer").Stream=videoStreamTheora;// VideoStreamPlayer's Autoplay property won't work if the stream is empty// before this property is set, so call `Play()` after setting `Stream`.GetNode<VideoStreamPlayer>("VideoStreamPlayer").Play();
3D scenes
Godot has first-class support for glTF 2.0, both in the editor and exportedprojects. UsingGLTFDocument andGLTFState together,Godot can load and save glTF files in exported projects, in both text(.gltf) and binary (.glb) formats. The binary format should be preferredas it's faster to write and smaller, but the text format is easier to debug.
Since Godot 4.3, FBX scenes can also be loaded (but not saved) at runtime using theFBXDocument andFBXState classes. The code to do sois the same as glTF, but you will need to replace all instances ofGLTFDocument andGLTFState withFBXDocument andFBXState in thecode samples below.
Example of loading a glTF scene and appending its root node to the scene:
# Load an existing glTF scene.# GLTFState is used by GLTFDocument to store the loaded scene's state.# GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,# which means it supports glTF features such as lights and cameras.vargltf_document_load=GLTFDocument.new()vargltf_state_load=GLTFState.new()varerror=gltf_document_load.append_from_file("/path/to/file.gltf",gltf_state_load)iferror==OK:vargltf_scene_root_node=gltf_document_load.generate_scene(gltf_state_load)add_child(gltf_scene_root_node)else:show_error("Couldn't load glTF scene (error code:%s)."%error_string(error))# Save a new glTF scene.vargltf_document_save:=GLTFDocument.new()vargltf_state_save:=GLTFState.new()gltf_document_save.append_from_scene(gltf_scene_root_node,gltf_state_save)# The file extension in the output `path` (`.gltf` or `.glb`) determines# whether the output uses text or binary format.# `GLTFDocument.generate_buffer()` is also available for saving to memory.gltf_document_save.write_to_filesystem(gltf_state_save,path)
// Load an existing glTF scene.// GLTFState is used by GLTFDocument to store the loaded scene's state.// GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,// which means it supports glTF features such as lights and cameras.vargltfDocumentLoad=newGltfDocument();vargltfStateLoad=newGltfState();varerror=gltfDocumentLoad.AppendFromFile("/Path/To/File.gltf",gltfStateLoad);if(error==Error.Ok){vargltfSceneRootNode=gltfDocumentLoad.GenerateScene(gltfStateLoad);AddChild(gltfSceneRootNode);}else{GD.PrintErr($"Couldn't load glTF scene (error code: {error}).");}// Save a new glTF scene.vargltfDocumentSave=newGltfDocument();vargltfStateSave=newGltfState();gltfDocumentSave.AppendFromScene(gltfSceneRootNode,gltfStateSave);// The file extension in the output `path` (`.gltf` or `.glb`) determines// whether the output uses text or binary format.// `GltfDocument.GenerateBuffer()` is also available for saving to memory.gltfDocumentSave.WriteToFilesystem(gltfStateSave,path);
Note
When loading a glTF scene, abase path must be set so that externalresources like textures can be loaded correctly. When loading from a file,the base path is automatically set to the folder containing the file. Whenloading from a buffer, this base path must be manually set as there is noway for Godot to infer this path.
To set the base path, setGLTFState.base_path on yourGLTFState instancebefore callingGLTFDocument.append_from_bufferorGLTFDocument.append_from_file.
Fonts
FontFile.load_dynamic_font supports the followingfont file formats: TTF, OTF, WOFF, WOFF2, PFB, PFM
On the other hand,FontFile.load_bitmap_font supportstheBMFont format (.fnt or.font).
Additionally, it is possible to load any font that is installed on the system usingGodot's support forSystem fonts.
Example of loading a font file automatically according to its file extension,then adding it as a theme override to aLabel node:
varpath="/path/to/font.ttf"varpath_lower=path.to_lower()varfont_file=FontFile.new()if(path_lower.ends_with(".ttf")orpath_lower.ends_with(".otf")orpath_lower.ends_with(".woff")orpath_lower.ends_with(".woff2")orpath_lower.ends_with(".pfb")orpath_lower.ends_with(".pfm")):font_file.load_dynamic_font(path)elifpath_lower.ends_with(".fnt")orpath_lower.ends_with(".font"):font_file.load_bitmap_font(path)else:push_error("Invalid font file format.")ifnotfont_file.data.is_empty():# If font was loaded successfully, add it as a theme override.$Label.add_theme_font_override("font",font_file)
stringpath="/Path/To/Font.ttf";varfontFile=newFontFile();if(path.EndsWith(".ttf",StringComparison.OrdinalIgnoreCase)||path.EndsWith(".otf",StringComparison.OrdinalIgnoreCase)||path.EndsWith(".woff",StringComparison.OrdinalIgnoreCase)||path.EndsWith(".woff2",StringComparison.OrdinalIgnoreCase)||path.EndsWith(".pfb",StringComparison.OrdinalIgnoreCase)||path.EndsWith(".pfm",StringComparison.OrdinalIgnoreCase)){fontFile.LoadDynamicFont(path);}elseif(path.EndsWith(".fnt",StringComparison.OrdinalIgnoreCase)||path.EndsWith(".font",StringComparison.OrdinalIgnoreCase)){fontFile.LoadBitmapFont(path);}else{GD.PrintErr("Invalid font file format.");}if(!fontFile.Data.IsEmpty()){// If font was loaded successfully, add it as a theme override.GetNode<Label>("Label").AddThemeFontOverride("font",fontFile);}
ZIP archives
Godot supports reading and writing ZIP archives using theZIPReaderandZIPPacker classes. This supports any ZIP file, including filesgenerated by Godot's "Export PCK/ZIP" functionality (although these will containimported Godot resources rather than the original project files).
Note
UseProjectSettings.load_resource_packto load PCK or ZIP files exported by Godot asadditional data packs. That approach is preferredfor DLCs, as it makes interacting with additional data packs seamless (virtual filesystem).
This ZIP archive support can be combined with runtime image, 3D scene and audioloading to provide a seamless modding experience without requiring users to gothrough the Godot editor to generate PCK/ZIP files.
Example that lists files in a ZIP archive in anItemList node,then writes contents read from it to a new ZIP archive (essentially duplicating the archive):
# Load an existing ZIP archive.varzip_reader=ZIPReader.new()zip_reader.open(path)varfiles=zip_reader.get_files()# The list of files isn't sorted by default. Sort it for more consistent processing.files.sort()forfileinfiles:$ItemList.add_item(file,null)# Make folders disabled in the list.$ItemList.set_item_disabled(-1,file.ends_with("/"))# Save a new ZIP archive.varzip_packer=ZIPPacker.new()varerror=zip_packer.open(path)iferror!=OK:push_error("Couldn't open path for saving ZIP archive (error code:%s)."%error_string(error))return# Reuse the above ZIPReader instance to read files from an existing ZIP archive.forfileinzip_reader.get_files():zip_packer.start_file(file)zip_packer.write_file(zip_reader.read_file(file))zip_packer.close_file()zip_packer.close()
// Load an existing ZIP archive.varzipReader=newZipReader();zipReader.Open(path);string[]files=zipReader.GetFiles();// The list of files isn't sorted by default. Sort it for more consistent processing.Array.Sort(files);foreach(stringfileinfiles){GetNode<ItemList>("ItemList").AddItem(file);// Make folders disabled in the list.GetNode<ItemList>("ItemList").SetItemDisabled(-1,file.EndsWith('/'));}// Save a new ZIP archive.varzipPacker=newZipPacker();varerror=zipPacker.Open(path);if(error!=Error.Ok){GD.PrintErr($"Couldn't open path for saving ZIP archive (error code: {error}).");return;}// Reuse the above ZIPReader instance to read files from an existing ZIP archive.foreach(stringfileinzipReader.GetFiles()){zipPacker.StartFile(file);zipPacker.WriteFile(zipReader.ReadFile(file));zipPacker.CloseFile();}zipPacker.Close();