目录

File Cache Boost (C/C++)

Starting from version 6.1.0(23), the file cache boost function has been added. A caching mechanism is provided to cache the decoded data of a file to the disk. When a user opens or browses the file again, the app can directly obtain the cached decoded data from the disk without executing the time-consuming decoding process.

API Description

For details about the APIs, please refer to the API reference.

Table 1 File cache APIs

API Description
bool HMS_Preview_FileCacheBoost_IsSupported (void) Checks whether the current device supports file cache boost. You are advised to use this API to check whether the device supports file cache boost. After confirming that the device supports this function, you can use other file cache boost APIs, such as HMS_FileCacheBoost_Init.

FileCacheBoost_ErrCode HMS_FileCacheBoost_Init (

const char* path, size_t pathLen, uint32_t cacheUpperLimitMb, const char* dbName, size_t dbNameLen)

Initializes the cache path, cache capacity upper limit, and database name. The system ensures thread concurrency security control. If multi-process concurrency scenarios need to be supported, it is recommended that each process use a different database file name to ensure access security.

FileCacheBoost_ErrCode HMS_FileCacheBoost_AddObjectByKey (

const uint8_t *key, size_t keyLen, const uint8_t *data, size_t dataLen, uint32_t weight)

Adds a cache to the system. The computed key is the unique identifier of the cache. You can pass the weight of the cache. The system will use this weight to compute the cache priority for capacity management. If you want a cache object to be retained with a higher priority, you should assign it a higher weight.

FileCacheBoost_ErrCode HMS_FileCacheBoost_GetObjectByKey (

const uint8_t *key, size_t keyLen, uint8_t **data, size_t *dataLen)

Obtains a cache based on the key.
FileCacheBoost_ErrCode HMS_FileCacheBoost_RemoveObjectByKey (const uint8_t *key, size_t keyLen) Deletes a cache based on the key.
FileCacheBoost_ErrCode HMS_FileCacheBoost_ClearAllCache (void) Deletes all caches.
FileCacheBoost_ErrCode HMS_FileCacheBoost_AddSerialObjectByKey (const uint8_t *key, size_t keyLen, SerializeFunc func, const void *object, uint32_t weight) Creates a cache item for a complex type object. A custom serialization function SerializeFunc is passed to serialize the object so that it can be stored on a disk and later restored.
FileCacheBoost_ErrCode HMS_FileCacheBoost_GetSerialObjectByKey (const uint8_t *key, size_t keyLen, DeserializeFunc func, void **object) Obtains a complex type object from the cache based on the specified key, and then restores it to its original data format using the passed deserialization function DeserializeFunc to obtain the complete object content.

Constraints

Supported device types: PCs/2-in-1 devices. Starting from version 26.0.0, tablets are also supported.

Development Procedure

  1. Add the corresponding header file.

    #include "PreviewKit/file_cache_boost.h"
    #include <string>
  2. Compile CMakeLists.txt and add the dependency on the file cache boost function.

    find_library(
        FILE_CACHE_BOOST
        NAMES libfile_cache_boost.so
        PATHS ${CMAKE_FIND_ROOT_PATH}/lib/aarch64-linux-ohos
    )
    # ...
    target_link_libraries(entry PUBLIC ${FILE_CACHE_BOOST})
  3. Initialize the cache path, cache capacity upper limit, and database name. The system will create the cache path and the corresponding database.

    napi_value OH_Init(napi_env env, napi_callback_info info) {
        // Obtain the number of parameters.
        size_t argc = 2; // Two parameters are required: path and cacheUpperLimitMb.
        napi_value args[2];
        napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
        // Check the number of parameters.
        if (argc < 2) {
            napi_throw_error(env, nullptr, "Invalid number of arguments");
            return nullptr;
        }
    
        // Obtain the path.
        size_t pathLen;
        char *path;
        napi_status status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &pathLen);
        if (status != napi_ok) {
            napi_throw_error(env, nullptr, "Failed to get path length");
            return nullptr;
        }
    
        // Allocate memory and obtain the path content.
        path = new char[pathLen + 1];
        napi_get_value_string_utf8(env, args[0], path, pathLen + 1, &pathLen);
    
        // Obtain cacheUpperLimitMb.
        uint32_t cacheUpperLimitMb;
        napi_get_value_uint32(env, args[1], &cacheUpperLimitMb);
    
        // Set the fixed dbName parameter.
        const char *dbName = "hwcache"; // hard-coded database name
        int32_t dbNameLen = static_cast<int32_t>(strlen(dbName));
        // You can enter a relative path, for example, ohcache. The unit of cacheUpperLimitMb is MB. 2 GB = 2048 MB.
        int result = HMS_FileCacheBoost_Init(path, pathLen, cacheUpperLimitMb, dbName, dbNameLen);
        if (result != FILE_CACHE_BOOST_SUCCESS) {
            // Initialization fails. You can customize error handling.
        }
        // Release the path memory.
        delete[] path;
    
        // Convert result to napi_value.
        napi_value jsResult;
        napi_create_int32(env, result, &jsResult);
    
        return jsResult;
    }
  4. Perform operations such as adding to persist required cache data to the disk, allowing it to be retrieved directly on the next use.

    napi_value OH_AddObjectByKey(napi_env env, napi_callback_info info) {
        // Obtain the number of parameters.
        size_t argc = 3;
        napi_value args[3];
        napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
        // Check the number of parameters.
        if (argc < 3) {
            napi_throw_error(env, nullptr, "Invalid number of arguments");
            return nullptr;
        }
    
        // Obtain the key.
        size_t keyLen;
        size_t fillStrLen;
        uint8_t *key = GetStringArg(env, args[0], keyLen);
        // Obtain the padding string.
        uint8_t *fillStr = GetStringArg(env, args[1], fillStrLen);
        if (!key || !fillStr) {
            delete[] key;
            delete[] fillStr;
            napi_throw_error(env, nullptr, "Key or fill string is empty");
            return nullptr;
        }
    
        // Obtain the memory size.
        uint32_t bufferMB;
        napi_get_value_uint32(env, args[2], &bufferMB);
        // Calculate the memory size.
        size_t bufferLen = static_cast<size_t>(bufferMB) * 1024 * 1024;
        // Allocate memory.
        uint8_t *buffer = new uint8_t[bufferLen];
    
        // Fill the memory with the padding string.
        for (size_t i = 0; i < bufferLen; i++) {
            buffer[i] = fillStr[i % fillStrLen]; // Fill cyclically with the padding string.
        }
    
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "add Get Key is : %{public}s, KeyLen: %{public}zu", key,
                 keyLen);
        uint32_t weight = 0;
        int result = isEableCancel
            ? ExecuteAddWithCancel(key, keyLen, buffer, bufferLen, weight)
            : HMS_FileCacheBoost_AddObjectByKey(key, keyLen, buffer, bufferLen, weight);
    
        v1.push_back(*key);
        delete[] key;
        delete[] fillStr;
        delete[] buffer;
        napi_value jsResult;
        napi_create_int32(env, result, &jsResult);
        return jsResult;
    }
  5. After the cache is added, you can call HMS_FileCacheBoost_GetObjectByKey to directly obtain the cached data.

    napi_value OH_GetObjectByKey(napi_env env, napi_callback_info info) {
        // Obtain the number of parameters.
        size_t argc = 1;
        napi_value args[1];
        napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
        // Check the number of parameters.
        if (argc < 1) {
            napi_throw_error(env, nullptr, "Invalid number of arguments");
            return nullptr;
        }
    
        // Obtain the key and keyLen.
        size_t keyLen;
        char *key;
        napi_get_value_string_utf8(env, args[0], nullptr, 0, &keyLen);
        key = new char[keyLen + 1];
        napi_get_value_string_utf8(env, args[0], key, keyLen + 1, &keyLen);
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "Get Key is : %{public}s", key);
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "Get KeyLen is : %{public}zu", keyLen);
    
        uint8_t *data = new uint8_t[500];
        size_t dataLen = 0;
    
        //Call HMS_FileCacheBoost_GetObjectByKey.
        int result = HMS_FileCacheBoost_GetObjectByKey(reinterpret_cast<uint8_t *>(key), keyLen, &data, &dataLen);
    
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "Data length: %{public}zu", dataLen);
        if (result != FILE_CACHE_BOOST_SUCCESS) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "key is no exits!");
            HMS_FileCacheBoost_FreeObject(data);
            delete[] key;
            napi_value jsResult;
            napi_create_int32(env, result, &jsResult);
            return jsResult;
        }
        if (data == nullptr || dataLen == 0) {
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "get object fail! and Data length: %{public}zu", dataLen);
            HMS_FileCacheBoost_FreeObject(data);
            delete[] key;
            napi_value jsResult;
            napi_create_int32(env, result, &jsResult);
            return jsResult;
        }
        size_t printLen = std::min(dataLen, static_cast<size_t>(100));
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "First 100 bytes of data:");
        for (size_t i = 0; i < printLen; ++i) {
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "Byte[%{public}zu]: %{public}c", i, data[i]);
        }
        HMS_FileCacheBoost_FreeObject(data);
        delete[] key;
        napi_value jsResult;
        napi_create_int32(env, result, &jsResult);
        return jsResult;
    }
  6. If you need to delete a cache that is no longer needed, call HMS_FileCacheBoost_RemoveObjectByKey.

    napi_value OH_RemoveObjectByKey(napi_env env, napi_callback_info info) {
        // Obtain the number of parameters.
        size_t argc = 1; // Only one parameter is required: key.
        napi_value args[1];
        napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
        // Check the number of parameters.
        if (argc < 1) {
            napi_throw_error(env, nullptr, "Invalid number of arguments");
            return nullptr;
        }
    
        // Obtain the key.
        napi_value keyArg = args[0];
    
        // Obtain the string information of the key.
        size_t keyLen;
        napi_get_value_string_utf8(env, keyArg, nullptr, 0, &keyLen); // Obtain the length of the key.
    
        // Allocate a buffer and obtain the key content.
        char *keyData = new char[keyLen + 1];
        napi_get_value_string_utf8(env, keyArg, keyData, keyLen + 1, &keyLen);
    
        // Call HMS_FileCacheBoost_RemoveObjectByKey to delete the cache.
        int result = HMS_FileCacheBoost_RemoveObjectByKey(reinterpret_cast<uint8_t *>(keyData), keyLen);
        // Add the return value indicating that the key does not exist.
        if (result != FILE_CACHE_BOOST_SUCCESS) {
            // Deletion fails. You can customize error handling.
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "RemoveObjectByKey error");
        }
        // Release the cache.
        delete[] keyData;
    
        // Return the result.
        napi_value jsResult;
        napi_create_int32(env, result, &jsResult);
        return jsResult;
    }
  7. To clear all caches, call HMS_FileCacheBoost_ClearAllCache.

    napi_value OH_ClearAllCache(napi_env env, napi_callback_info info) {
        int result = HMS_FileCacheBoost_ClearAllCache();
    
        // Return the result.
        napi_value jsResult;
        napi_create_int32(env, result, &jsResult);
        return jsResult;
    }
  8. When a thread attempts to delete a data object, another thread may be performing the HMS_FileCacheBoost_AddObjectByKey operation on the data object. In this case, you can call HMS_FileCacheBoost_CancelOngoingIOByKey to cancel the ongoing I/O operation on the cache object corresponding to the key.

    napi_value OH_CancelAllOperation(napi_env env, napi_callback_info info) {
        // Obtain the number of parameters.
        size_t argc = 1; // Only one parameter is required: key.
        napi_value args[1];
        napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
        // Check the number of parameters.
        if (argc < 1) {
            napi_throw_error(env, nullptr, "Invalid number of arguments");
            return nullptr;
        }
    
        // Obtain the string information of the key.
        size_t keyLen;
        napi_get_value_string_utf8(env, args[0], nullptr, 0, &keyLen); // Obtain the length of the key.
    
        // Allocate a buffer and obtain the key content.
        uint8_t *keyData = new uint8_t[keyLen + 1];
        napi_get_value_string_utf8(env, args[0], reinterpret_cast<char *>(keyData), keyLen + 1, &keyLen);
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "OH_CancelAllOperation keyArg: %{public}s",
                     reinterpret_cast<uint8_t *>(keyData));
        // Call HMS_FileCacheBoost_CancelOngoingIOByKey.
        int result =
            HMS_FileCacheBoost_CancelOngoingIOByKey(reinterpret_cast<uint8_t *>(keyData), static_cast<size_t>(keyLen));
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "OH_CancelAllOperation result: %{public}d", result);
        delete[] keyData;
    
        // Return the result.
        napi_value jsResult;
        napi_create_int32(env, result, &jsResult);
        return jsResult;
    }
  9. If the cached data is attached to an object of a complex class that contains unmanageable data structures (such as other complex objects or pointers), the data cannot be recovered after being saved to the disk unless it is preserved together. For such complex data, you need to provide a serialization function.

    // Serialization function: serializes the ImageData object into a byte stream.
    FileCacheBoost_CbErrCode Serialize(const void *object, WriteFunc write, struct CacheKey *key) {
        // 1. Verify parameters.
        if (object == nullptr || write == nullptr || key == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "Serialize: invalid parameters!");
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        const struct ImageData* img = static_cast<const struct ImageData*>(object);
        // 2. Check data validity.
        if (img->width == 0 || img->height == 0 || img->pixels == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "Serialize: invalid image data! width=%{public}u, height=%{public}u",
                         img->width, img->height);
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        // 3. Calculate the data size.
        size_t metaDataSize = sizeof(uint32_t) * 2;  // width + height
        size_t imageSize = img->width * img->height * sizeof(uint8_t);
        size_t totalSize = metaDataSize + imageSize;
        // 4. Allocate a buffer (one-time write policy for performance optimization).
        uint8_t *buffer = new (std::nothrow) uint8_t[totalSize];
        if (buffer == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "Serialize: memory allocation failed! size=%{public}zu", totalSize);
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        // 5. Fill in the metadata (little endian).
        uint8_t *ptr = buffer;
        // Write the width (4 bytes, little endian).
        *ptr++ = static_cast<uint8_t>(img->width & 0xFF);
        *ptr++ = static_cast<uint8_t>((img->width >> 8) & 0xFF);
        *ptr++ = static_cast<uint8_t>((img->width >> 16) & 0xFF);
        *ptr++ = static_cast<uint8_t>((img->width >> 24) & 0xFF);
        // Write the height (4 bytes, little endian).
        *ptr++ = static_cast<uint8_t>(img->height & 0xFF);
        *ptr++ = static_cast<uint8_t>((img->height >> 8) & 0xFF);
        *ptr++ = static_cast<uint8_t>((img->height >> 16) & 0xFF);
        *ptr++ = static_cast<uint8_t>((img->height >> 24) & 0xFF);
        // 6. Copy pixel data.
        std::copy(img->pixels, img->pixels + imageSize, ptr);
        // 7. Write all data at once (for performance optimization).
        FileCacheBoost_ErrCode errorCode = write(buffer, totalSize, key);
        // 8. Release the cache.
        delete[] buffer;
        if (errorCode == FILE_CACHE_BOOST_SUCCESS) {
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG,
                         "Serialize success! width=%{public}u, height=%{public}u, size=%{public}zu",
                         img->width, img->height, totalSize);
            return FILE_CACHE_BOOST_CALLBACK_SUCCESS;
        } else {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "Serialize: write failed! errorCode=%{public}d", errorCode);
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
    }
  10. Call HMS_FileCacheBoost_AddSerialObjectByKey to add the serialized cache of complex data.

    napi_value OH_AddSerialObjectByKey(napi_env env, napi_callback_info info) {
        size_t argc = 3;
        napi_value args[3];
        napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
        // Check the number of parameters.
        if (argc < 3) {
            napi_throw_error(env, nullptr, "Invalid number of arguments");
            return nullptr;
        }
        // Obtain the key.
        char* key1;
        size_t keyLen;
        napi_get_value_string_utf8(env, args[0], nullptr, 0, &keyLen);
        key1 = new char[keyLen + 1];
        napi_get_value_string_utf8(env, args[0], key1, keyLen + 1, &keyLen);
        // Obtain the width and height (received as strings and then converted to numbers).
        char* widthStr = nullptr;
        size_t widthStrLen = 0;
        napi_get_value_string_utf8(env, args[1], nullptr, 0, &widthStrLen);
        widthStr = new char[widthStrLen + 1];
        napi_get_value_string_utf8(env, args[1], widthStr, widthStrLen + 1, &widthStrLen);
        uint32_t width = static_cast<uint32_t>(atoi(widthStr));
        char* heightStr = nullptr;
        size_t heightStrLen = 0;
        napi_get_value_string_utf8(env, args[2], nullptr, 0, &heightStrLen);
        heightStr = new char[heightStrLen + 1];
        napi_get_value_string_utf8(env, args[2], heightStr, heightStrLen + 1, &heightStrLen);
        uint32_t height = static_cast<uint32_t>(atoi(heightStr));
        // Construct an ImageData object.
        struct ImageData* img = new (std::nothrow) ImageData();
        if (img == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "OH_AddSerialObjectByKey: ImageData allocation failed!");
            delete[] widthStr;
            delete[] heightStr;
            delete[] key1;
            napi_value jsResult;
            napi_create_int32(env, FILE_CACHE_BOOST_ERROR_NOMEM, &jsResult);
            return jsResult;
        }
        img->width = width;
        img->height = height;
        img->pixels = new (std::nothrow) uint8_t[width * height];
        if (img->pixels == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "OH_AddSerialObjectByKey: pixels allocation failed!");
            delete img;
            delete[] widthStr;
            delete[] heightStr;
            delete[] key1;
            napi_value jsResult;
            napi_create_int32(env, FILE_CACHE_BOOST_ERROR_NOMEM, &jsResult);
            return jsResult;
        }
        // Fill in test data ('a', 'b', 'c' loop).
        for (size_t i = 0; i < width * height; i++) {
            img->pixels[i] = 'a' + (i % 3);
        }
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG,
                     "HMS_FileCacheBoost_AddSerialObjectByKey: key=%{public}s, width=%{public}u, height=%{public}u",
                     key1, width, height);
        uint32_t weight = 100;
        // Add a data cache for a complex class.
        int result = HMS_FileCacheBoost_AddSerialObjectByKey(
            reinterpret_cast<uint8_t*>(key1), keyLen, Serialize, img, weight
        );
        // Release the temporary object (data has been serialized to the cache).
        delete[] img->pixels;
        delete img;
        // Convert result to napi_value.
        napi_value jsResult;
        napi_create_int32(env, result, &jsResult);
        delete[] widthStr;
        delete[] heightStr;
        delete[] key1;
        return jsResult;
    }
  11. For data cached in serialized mode, you need to provide a deserialization function when obtaining the data.

    // Deserialization function: Restore the ImageData object from the byte stream.
    FileCacheBoost_CbErrCode Deserialize(void **object, ReadFunc read, struct CacheKey *key) {
        // 1. Verify parameters.
        if (object == nullptr || read == nullptr || key == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "Deserialize: invalid parameters!");
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        // 2. Read the metadata header (8 bytes: width + height).
        uint8_t header[8];
        size_t headerSize = 8;
        FileCacheBoost_ErrCode errorCode = read(header, &headerSize, key);
        if (errorCode != FILE_CACHE_BOOST_SUCCESS || headerSize != 8) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "Deserialize: read header failed! errorCode=%{public}d, size=%{public}zu",
                         errorCode, headerSize);
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        // 3. Parse the metadata (little endian).
        uint32_t width = static_cast<uint32_t>(
            header[0] | (header[1] << 8) | (header[2] << 16) | (header[3] << 24)
        );
        uint32_t height = static_cast<uint32_t>(
            header[4] | (header[5] << 8) | (header[6] << 16) | (header[7] << 24)
        );
        // 4. Check data validity.
        if (width == 0 || height == 0 || width > 10000 || height > 10000) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "Deserialize: invalid dimensions! width=%{public}u, height=%{public}u",
                         width, height);
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        // 5. Calculate the space occupied by image data.
        size_t imageSize = width * height * sizeof(uint8_t);
        // 6. Allocate memory for the ImageData struct.
        struct ImageData* img = new (std::nothrow) struct ImageData;
        if (img == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "Deserialize: ImageData allocation failed!");
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        // 7. Allocate memory for pixel data.
        img->pixels = new (std::nothrow) uint8_t[imageSize];
        if (img->pixels == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "Deserialize: pixels allocation failed! size=%{public}zu", imageSize);
            delete img;
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        // 8. Set image attributes.
        img->width = width;
        img->height = height;
        // 9. Read pixel data.
        size_t pixelSize = imageSize;
        errorCode = read(img->pixels, &pixelSize, key);
        if (errorCode != FILE_CACHE_BOOST_SUCCESS || pixelSize != imageSize) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "Deserialize: read pixels failed! errorCode=%{public}d, expected=%{public}zu, actual=%{public}zu",
                         errorCode, imageSize, pixelSize);
            delete[] img->pixels;
            delete img;
            return FILE_CACHE_BOOST_CALLBACK_FAILURE;
        }
        // 10. Correctly set the output parameters (fixing a bug).
        *object = static_cast<void*>(img);
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG,
                     "Deserialize success! width=%{public}u, height=%{public}u, size=%{public}zu",
                     width, height, imageSize);
        return FILE_CACHE_BOOST_CALLBACK_SUCCESS;
    }
  12. Call HMS_FileCacheBoost_GetSerialObjectByKey to obtain the cached data.

    napi_value OH_GetSerialObjectByKey(napi_env env, napi_callback_info info) {
        // Obtain the number of parameters.
        size_t argc = 1;
        napi_value args[1];
        napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
        // Check the number of parameters.
        if (argc < 1) {
            napi_throw_error(env, nullptr, "Invalid number of arguments");
            return nullptr;
        }
        char *key;
        size_t keyLen;
        napi_get_value_string_utf8(env, args[0], nullptr, 0, &keyLen);
        key = new char[keyLen + 1];
        napi_get_value_string_utf8(env, args[0], key, keyLen + 1, &keyLen);
    
        // Define an object.
        void *object = nullptr;
        // Call HMS_FileCacheBoost_GetSerialObjectByKey to obtain the data cache for a complex class.
        int result = HMS_FileCacheBoost_GetSerialObjectByKey(
            reinterpret_cast<uint8_t*>(key), keyLen, Deserialize, &object
        );
        if (result == FILE_CACHE_BOOST_SUCCESS && object != nullptr) {
            // Output the image information if data is obtained successfully.
            struct ImageData* img = static_cast<struct ImageData*>(object);
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG,
                         "GetSerialObject success! width=%{public}u, height=%{public}u",
                         img->width, img->height);
            // Print some pixel data (the first 100 bytes).
            size_t printLen = std::min(img->width * img->height, static_cast<uint32_t>(100));
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG, "First %{public}zu pixels:", printLen);
            for (size_t i = 0; i < printLen; i++) {
                OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, LOG_TAG,
                             "Pixel[%{public}zu]=%{public}c", i, img->pixels[i]);
            }
            // Release the memory of the ImageData object.
            delete[] img->pixels;
            delete img;
        } else {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG,
                         "GetSerialObject failed! result=%{public}d", result);
        }
        // Release the memory.
        delete[] key;
    
        // Return the result.
        napi_value jsResult;
        napi_create_int32(env, result, &jsResult);
        return jsResult;
    }