Skip to content

z-libs/zfile.h

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zfile.h

zfile.h is a cross-platform File I/O and Path Manipulation library for C. It abstracts away the messy differences between Windows (Win32 API) and POSIX systems, providing a unified, pragmatic API for file system operations.

It is designed to work seamlessly with zstr.h for string handling and includes a robust C++11 wrapper for RAII-style path manipulation and directory iteration.

It is part of the zdk suite.

Features

  • Cross-Platform: Unified API for Windows and Linux/macOS. Handles UTF-8 paths correctly on Windows (automatically converts to wchar_t).
  • Atomic Saves: zfile_save_atomic writes to a temporary file and renames it, preventing data corruption during crashes.
  • Recursive Operations: zfile_mkdir_recursive creates full directory trees (like mkdir -p).
  • Buffered Reading: High-performance, zero-copy line reader (ZFILE_FOR_EACH_LINE) for parsing large files.
  • Path Logic: Smart path joining, extension extraction, and normalization using zstr.
  • C++ Support: Includes z_file::path (operator / overloading) and range-based directory iterators.
  • Header Only: No linking required.

Installation

Manual

zfile.h depends on zstr.h and zcommon.h.

  1. Download zfile.h, and zstr.h. You can also clone the repository and do:
make
# or
make get_dependencies
  1. Include it in one C/C++ file with the implementation macros defined (ZFILE_IMPLEMENTATION and ZSTR_IMPLEMENTATION).
#define ZFILE_IMPLEMENTATION
#include "zfile.h"

Clib

If you use the clib package manager, you can install the z-libs/zdk package.

clib install z-libs/zdk

ZDK (Recommended)

If you use the Zen Development Kit, it is included automatically by including <zdk/zfile.h> (or <zdk/zworld.h>).

Usage: C

To use the library in C, simply include the header. Access path manipulation functions to handle cross-platform separators, use the atomic save functions for safe file writing, and use the buffered reader macros for efficient parsing.

#include <stdio.h>

#define ZFILE_IMPLEMENTATION
#include "zfile.h"

int main(void)
{
    // => Path manipulation.
    //    (Automatically handles '/' vs '\' separators).
    zstr path = zfile_join("data", "config.json");
    
    if (zfile_exists(zstr_cstr(&path))) 
    {
        printf("Config found at: %s\n", zstr_cstr(&path));
    }

    // => Atomic write.
    //    Writes to "data/config.json.tmp_XXXX" then renames.
    const char *data = "{\"version\": 1}";
    if (zfile_save_atomic(zstr_cstr(&path), data, strlen(data)) == Z_OK) 
    {
        printf("Saved successfully.\n");
    }

    // Buffered line reader (zero-copy views).
    ZFILE_FOR_EACH_LINE("data/logs.txt", line) 
    {
        // 'line' is a zstr_view (ptr + len), not a null-terminated string.
        printf("Log: %.*s\n", (int)line.len, line.data);
    }

    zstr_free(&path);
    return 0;
}

Usage: C++

The C++ wrapper lives in the z_file namespace. It provides a std::filesystem-like experience but is much lighter to compile. You can use z_file::path for RAII path manipulation and z_file::dir_iterable for range-based directory loops.

#include <iostream>
#define ZFILE_IMPLEMENTATION
#include "zfile.h"

int main()
{
    // => Path wrapper (RAII).
    z_file::path root = "assets";
    z_file::path model = root / "models" / "hero.obj";

    std::cout << "Loading: " << model.c_str() << "\n";
    std::cout << "Extension: " << std::string(model.extension()) << "\n";

    // => Directory iteration (Range-based).
    if (root.exists() && root.is_dir()) 
    {
        for (auto entry : z_file::dir_iterable(root)) 
        {
            // entry.name is a char array.
            // entry.type is ZDIR_FILE or ZDIR_DIR.
            std::cout << "Found: " << entry.name << "\n";
        }
    }

    return 0;
}

API Reference (C)

Path Manipulation

Function Description
zfile_join(base, child) Returns a new zstr joining two paths with the correct OS separator.
zfile_ext(path) Returns a zstr_view of the file extension (e.g., .txt).
zfile_base(path) Returns a zstr_view of the filename (basename).
zfile_dir(path) Returns a zstr_view of the parent directory.
zfile_normalize(zstr*) Modifies a zstr in-place, converting separators to the OS standard.
zfile_tempname(pfx, ext) Generates a unique path in the system temp directory (e.g., /tmp/pfx_123.ext).

File I/O

Function Returns Description
zfile_exists(path) bool Returns true if the path exists.
zfile_is_dir(path) bool Returns true if the path exists and is a directory.
zfile_is_file(path) bool Returns true if the path exists and is a regular file.
zfile_size(path) int64_t Returns file size in bytes, or -1 on error.
zfile_read_all(path) zstr Reads entire file into memory. Returns empty string on failure.
zfile_write_all(path, ...) int Writes buffer to file (overwrite). Returns 0 or error code.
zfile_append(path, ...) int Appends buffer to file.
zfile_save_atomic(path, ...) int Recommended. Writes to temp file, then renames. Safe against crashes.
zfile_copy(src, dst) int Copies a file chunk-by-chunk.
zfile_remove(path) int Deletes a file.
zfile_rename(old, new) int Renames/Moves a file.

Directories

Function Description
zfile_mkdir_recursive(path) Creates a directory and all its parents (like mkdir -p).
zdir_open(path) Opens a directory iterator (zdir_iter*).
zdir_next(it, entry*) Advances iterator. Returns true if an entry was found.
zdir_close(it) Frees the iterator.

Buffered Reading

Macro / Function Description
zfile_reader_open(path) Opens a file for buffered reading. Allocates internal buffer.
zfile_reader_next_line(r, line*) Zero-copy parse. line points inside the buffer. Returns false on EOF.
ZFILE_FOR_EACH_LINE(path, var) Macro: Automates open, loop, and close. var is declared as zstr_view.

API Reference (C++)

The C++ wrapper classes are lightweight and wrap zstr objects.

class z_file::path

Method Description
path(const char*) Constructor.
operator/(other) Joins paths using the OS separator. Returns new path.
exists() Returns true if path exists.
is_dir() Returns true if path is a directory.
extension() Returns z_str::view of the extension.
string() Returns the underlying z_str::string.
c_str() Returns const char*.

class z_file::dir_iterable

Designed for range-based for loops.

Method Description
dir_iterable(path) Constructor.
begin(), end() Standard iterators.
for (auto entry : z_file::dir_iterable("some/path")) 
{
    if (entry.type == ZDIR_FILE) { ... }
}

Short Names (Opt-In)

If you prefer a cleaner API and don't have naming conflicts, define ZFILE_SHORT_NAMES before including the header.

Short Name Original
file_exists zfile_exists
path_join zfile_join
file_read zfile_read_all
file_write zfile_write_all
dir_open zdir_open
dir_next zdir_next
file_foreach_line ZFILE_FOR_EACH_LINE

Dependencies

  • zstr.h: Required for path string manipulation.
  • zcommon.h: Required for standard types and definitions. Bundled.

About

A cross-platform, header-only file system library for C/C++ that simplifies path manipulation, file I/O, and directory traversal.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

  •  

Packages

 
 
 

Contributors