Modules

File

moduleSource
macOSLinuxWindowswasm

#import "File";

Opening, reading, writing and managing files and directories by path.

A File is a handle from file_open; read_entire_file and write_entire_file do a whole file in one call, and map_entire_file_start borrows the content. Names are UTF-8 paths, with / as separator on every target (Windows accepts \ as well). Every procedure reports failure by its result and does not stop the program. Memory a procedure returns comes from context.allocator and the caller frees it. Walking directories, copying and metadata are in File_Utilities.

ExampleOpen in playground ↗
#import "Extensions/Environment";
base := environment_variable("TMPDIR");
if base == "" base = environment_variable("TEMP");
if base == "" base = "/tmp";
path := tprint("%/jai-doc-file-module.txt", base);
defer file_delete(path);

assert(write_entire_file(path, "hello\n"));
text, ok := read_entire_file(path);
assert(ok && text == "hello\n");
free(text);

Procedures#

Native Windows#

(name: string, for_writing := false, keep_existing_content := false, log_errors := false) -> (File, bool)

Opens the file name and returns it with true, or a closed file and false when that fails.

(file: *File)

Closes file and sets it to the closed state. A file that is already closed, or was never opened, is left alone, so closing twice is safe. A failure to close is logged and leaves the handle as it was.

(file: File) -> bool

Whether file is open: false for a zero File, for one file_open failed to open, and for one file_close closed.

(f: File, vdata: *void, bytes_to_read: s64) -> (success: bool, total_read: s64)

Reads up to bytes_to_read bytes from the current position into vdata, and returns (success, total_read).

(f: File) -> (s64, bool)

The position of the next read or write, in bytes from the start of the file, and whether it could be read. A closed file gives (0, false).

(f: File, pos: s64) -> bool

Moves to byte pos counted from the start of the file. Returns false for a closed file or a negative pos.

(file: File, pos: s64, type: Seek_Type) -> success: bool

Moves by pos bytes relative to .START, .CURRENT or .END of the file. A negative pos goes backwards. Returns false for a closed file or when the result would be before the start. Going past the end is allowed.

(file: File) -> (s64, bool)

The size of the file in bytes and whether it could be read. The position does not change.

(file: File) -> bool

Asks the system to write the file's buffers to the device (FlushFileBuffers); returns false for a closed file or on an error.

(name_old: string, name_new: string) -> bool

Renames the file name_old to name_new, which may be on another volume. Returns false if that fails, including when name_new already exists: delete it first, or see File_Utilities.atomic_file_replace_or_just_rename_if_destination_file_does_not_exist.

(filename: string) -> bool

Deletes the file filename; false if it does not exist, is a directory (see delete_directory) or is read-only. Files this module opened can be deleted while open.

(dirname: string) -> bool

Removes the directory dirname if it is empty. Returns false if it is missing, not empty, or not a directory. To remove a folder with its content, see File_Utilities.delete_directory_tree.

(name: string, recursive := false) -> directory_now_exists: bool

Makes sure the directory name exists and returns whether it does afterwards: an existing directory is a success, a file of that name or (without recursive) a missing parent is a failure. With recursive, missing parents are created too. Both / and \ work as separators.

(relative_path: string) -> (string, success: bool)

The absolute form of relative_path, in a new string from context.allocator that the caller frees, and whether it worked.

map_fileWindows
(name: string, log_errors := false) -> (File_Map_Info, bool)

Maps the whole file name for reading and returns ok; an empty file succeeds with empty data. Give the result to munmap_file. A failure is logged through context.logger when log_errors is true, and nothing needs releasing then.

(file_map: *File_Map_Info) -> bool

Releases a File_Map_Info: unmaps the view, closes the mapping and the file. Safe to call again on the same record; returns false if the system refuses.

() -> string

The path of the machine-wide application data folder (ProgramData), created if missing, in a new UTF-8 string the caller frees; "" on failure.

() -> string

The path of the current user's Saved Games folder, created if missing, in a new UTF-8 string the caller frees; "" on failure.

file_get_canonical_path2 overloadsWindows
(file: File) -> string

The final path of an open file, with links followed, in a new string that the caller frees; "" when file is closed or the system cannot say. Windows spells it with the \\?\ prefix and \ separators.

File#

(file: File) -> (success: bool, position: s64)

The current position of file as (success, position).

file_write2 overloads
(file: *File, data: string) -> bool

Writes all of data to file. Returns false when the file is not open or the write fails or stops short.

read_entire_file2 overloads
(f: File, zero_terminated := false) -> (string, bool)

Reads the rest of an open file, from its current position to its end, into a new string.

#import "Extensions/Environment";
base := environment_variable("TMPDIR");
if base == "" base = environment_variable("TEMP");
if base == "" base = "/tmp";
path := tprint("%/jai-doc-read-rest.bin", base);
defer file_delete(path);

assert(write_entire_file(path, "abcdef"));
file, ok := file_open(path);
assert(ok);
defer file_close(*file);

assert(file_set_position(file, 2));
rest, read_ok := read_entire_file(file, zero_terminated = true);
assert(read_ok && rest == "cdef" && rest.data[rest.count] == 0);
free(rest);
↗
(name: string, data: string) -> bool

Replaces the file name with data: it is created if missing and cut to nothing otherwise. Returns false when it cannot be opened, written or flushed.

#import "Extensions/Environment";
base := environment_variable("TMPDIR");
if base == "" base = environment_variable("TEMP");
if base == "" base = "/tmp";
path := tprint("%/jai-doc-write-entire.txt", base);
defer file_delete(path);

assert(write_entire_file(path, "a long first version"));
assert(write_entire_file(path, "short"));
text, ok := read_entire_file(path);
assert(ok && text == "short");
free(text);
assert(!write_entire_file(tprint("%/jai-doc-no-such-dir/file", base), "x"));
↗
(name: string, log_errors := false) -> (Map_File_Info, bool)

Gives a file's whole content as Map_File_Info.data; returns ok as false and empty data when the file cannot be read.

#import "Extensions/Environment";
base := environment_variable("TMPDIR");
if base == "" base = environment_variable("TEMP");
if base == "" base = "/tmp";
path := tprint("%/jai-doc-map-file.txt", base);
defer file_delete(path);

assert(write_entire_file(path, "mapped text"));
info, ok := map_entire_file_start(path);
assert(ok && info.data == "mapped text");
map_entire_file_end(*info);
assert(info.data.count == 0);
↗
(file_info: *Map_File_Info)

Releases what map_entire_file_start returned and leaves data empty: it unmaps the view on Windows and frees the text elsewhere. Do not use the old data afterwards. A failure to unmap is logged and data keeps its value.

Types#

Filestruct
:: struct

An open file. It holds the operating system's HANDLE and nothing else, so a copy of a File is the same open file, not a second one. Get one from file_open, and give it back with file_close exactly once.

:: struct

A whole file's bytes, as map_entire_file_start returns them: data is the content, and the record must go back to map_entire_file_end.

File_Map_InfostructWindows
:: struct

A read-only view of a whole file, from map_file: data is its content, mapping the mapping object and file the open file. Give it back to munmap_file. Writing to data faults.

Constants#

:: OS == .WINDOWS

Whether map_entire_file_start maps the file into memory (Windows) or reads it into allocated memory (every other target).

:: false

A switch kept for programs that mention it; it is always false and nothing in the module reads it.

:: 0x7fffffffffffffff

The largest s64, kept for programs that compare against it. No procedure of this module returns it. Unix targets only.

:: 0x001a

The legacy folder id of the roaming application data folder, for Windows APIs that take one. Windows only.

:: 0x00008000

The known-folder flag that creates the folder when it is missing, as get_path_os_program_data and get_path_os_saved_games ask for. Windows only.

:: "4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4"

The text form of the known-folder id of the Saved Games folder. Windows only.