libnpy: Easily Read and Write NumPy Data Files with C++

πŸ“Š libnpy: Easily Read and Write NumPy Data Files with C++

Have you encountered the following scenarios while developing C++ projects?

“How do I load model weights trained with NumPy in Python into C++?”
“How can a C++ program read sensor data in .npy format?”
“Is there a simple way to share array data between C++ and Python?”

Today, we will introduce a lightweight, dependency-free, header-only C++ library β€” libnpy.

It allows you to easily:

  • βœ… Read .npy files (NumPy single array)
  • βœ… Read .npz files (NumPy multi-array compressed package)
  • βœ… Write .npy and .npz files
  • βœ… Seamlessly exchange numerical data between C++ and Python

Project address: https://github.com/llohse/libnpy
License: MIT (commercial use allowed)

πŸ” What is libnpy?

libnpy is an open-source C++ library developed by Lars LΓΆhhse, designed specifically for reading and writing NumPy’s .npy and .npz file formats.

βœ… Core Features

Feature Description
🧩 Header-only Simply include one .hpp file, no compilation needed
πŸ“¦ No external dependencies No reliance on large libraries like Boost or Eigen
🧠 Automatic type inference Automatically recognizes NumPy data types (float32, int64, etc.)
πŸ“ Supports multi-dimensional arrays Supports 1D to 7D arrays (NumPy limitation)
πŸ’Ύ Supports .npz compressed packages Reads multiple arrays from .npz
πŸ†“ MIT License Can be used for commercial projects

⚠️ Note: It does not support complex NumPy types like datetime or object, focusing on numerical arrays (int, float).

πŸ› οΈ Installation and Integration

Method 1: Directly Download the Header File (Recommended)

wget https://raw.githubusercontent.com/llohse/libnpy/master/include/npy.hpp

Then in your C++ code:

#include "npy.hpp"

It’s that simple! No compilation, no linking required.

πŸ’‘ First Example: Generate .npy File with Python

First, create a test file using Python:

βœ… create_data.py

import numpy as np

# Create a 3x4 float array
data = np.random.rand(3, 4).astype(np.float32)
print("Data in Python:")
print(data)

# Save as .npy file
np.save("data.npy", data)

# You can also save multiple arrays to .npz
np.savez("data.npz", array1=data, array2=np.array([1, 2, 3]))

Run it:

python create_data.py

This will generate data.npy and data.npz.

πŸ’‘ Second Example: Read .npy File with C++

βœ… read_npy.cpp

#include "npy.hpp"
#include <iostream>
#include <vector>

int main() {
    // 1. Read .npy file
    auto array = npy::read_npy<float>("data.npy");

    // 2. Get array information
    std::cout << "Dimensions: ";
    for (auto dim : array.shape) {
        std::cout << dim << " ";
    }
    std::cout << "\nData type: " << array.fortran_order << "\n";

    // 3. Access data (row-major order)
    std::cout << "Data read in C++:\n";
    for (size_t i = 0; i < array.shape[0]; ++i) {
        for (size_t j = 0; j < array.shape[1]; ++j) {
            // Calculate index: row-major order
            size_t idx = i * array.shape[1] + j;
            std::cout << array.data[idx] << " ";
        }
        std::cout << "\n";
    }

    return 0;
}

βœ… Compile and Run

g++ read_npy.cpp -o read_npy
./read_npy

πŸŽ‰ Sample Output:

Dimensions: 3 4
Data type: 0
Data read in C++:
0.123 0.456 0.789 0.234 
0.567 0.890 0.345 0.678 
0.901 0.234 0.567 0.890 

Perfectly matches the data generated in Python!

πŸ“₯ Write to .npy File

βœ… write_npy.cpp

#include "npy.hpp"
#include <vector>

int main() {
    // Create a 2x3 array
    std::vector<float> data = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
    std::vector<size_t> shape = {2, 3};

    // Write to .npy file
    npy::save_npy("output.npy", data.data(), shape, false); // false = not fortran order

    std::cout << "Saved output.npy\n";
    return 0;
}

Verify with Python:

import numpy as np
loaded = np.load("output.npy")
print(loaded)
# Output: [[1. 2. 3.]
#        [4. 5. 6.]]

πŸ“¦ Read .npz File (Multiple Arrays)

.npz is a ZIP compressed package containing multiple .npy files.

βœ… read_npz.cpp

#include "npy.hpp"
#include <iostream>

int main() {
    // Read .npz file
    auto archive = npy::read_npz("data.npz");

    std::cout << "Found " << archive.size() << " arrays\n";

    for (const auto& pair : archive) {
        const std::string& name = pair.first;
        const auto& array = pair.second;

        std::cout << "Array name: " << name << "\n";
        std::cout << "Shape: ";
        for (auto dim : array.shape) {
            std::cout << dim << " ";
        }
        std::cout << "\n";

        // Print the first element (example)
        if (!array.data.empty()) {
            std::cout << "First element: " << array.data[0] << "\n";
        }
    }

    return 0;
}

🌐 Supported Data Types

libnpy automatically maps NumPy types to C++ types:

NumPy Type C++ Type
int8 int8_t
int16 int16_t
int32 int32_t
int64 int64_t
uint8 uint8_t
float32 float
float64 double
complex64 std::complex<float>
complex128 std::complex<double>

When using, simply specify the template parameter, such as npy::read_npy<float>().

🧩 Advanced Tips

1. Integration with Eigen (Common Requirement)

Although libnpy does not directly depend on Eigen, you can easily convert:

#include <Eigen/Dense>
// ...
auto array = npy::read_npy<float>("matrix.npy");
Eigen::Map<Eigen::MatrixXf> mat(array.data.data(), array.shape[0], array.shape[1]);

2. Memory Safety

  • array.data is std::vector<T>, automatically managing memory.
  • No need to manually free.

🌍 Real-world Applications

Scenario Description
AI Inference Loading weights trained in Python with C++
Scientific Computing Sharing experimental data
Embedded Systems Loading calibration parameters
Game Development Loading precomputed numerical tables
Cross-language Projects Python processing + C++ high-performance computing

βœ… Why Choose libnpy?

Comparison Item libnpy Manual Parsing Other Libraries (e.g., cnpy)
Ease of Use βœ… Header-only ❌ Complex ⚠️ May require compilation
Dependencies βœ… None β€” May depend on zlib
Functionality βœ… .npy + .npz Limited Similar
Maintainability βœ… Active β€” Depends on the project

πŸ“š Learning Resources

βœ… Summary

libnpy is a bridge for C++ developers to seamlessly connect with the Python scientific computing ecosystem.

It:

🧩 Minimal integration
πŸ“¦ Zero dependencies
πŸ”„ Efficient exchange
πŸ†“ Free to use

Whether you are working on AI, simulation, or data processing, as long as your workflow involves data generated by Python and processed by C++, libnpy is an indispensable tool for you.

“Let data flow freely between languages.”

Now add it to your C++ project and start your cross-language collaboration journey!

Leave a Comment