saveRDS: Serialize an R object to a connection.

Description Usage Arguments Details Value Note Examples

Description

This version of readRDS and saveRDS provides capabilities to define serializers for non-native R objects (such as external pointers to C structures).

Usage

1
2
3
saveRDS(object, ...)

readRDS(file, ...)

Arguments

object

ANY. The R object to serialize to a file. This object should have an attribute with the name "RDS2.serialize" if the RDS2 package capabilities for serializing and deserializing non-native R objects wish to be used. It should consist of a list with one or both of the keys read and write that take the object as input and convert a vanilla-to-non-vanilla and non-vanilla-to-vanilla R object, respectively. (Here, non-vanilla means it may reference non-native R objects, such as external pointers to C structures).

If the "RDS2.serialize" attribute has the list element side_effects = FALSE, an additional deserialization step will not be executed during saveRDS. This can be used to slightly speed up that function. For example, if saveRDS is serializing a reference class object or environment, where the write function can have side effects on the object, we must be careful to undo these effects. Setting attr(object, "RDS2.serialize")$side_effects = FALSE, we skip this reversal, if we are confident the serialization procedure does not affect the object or any of its components.

...

arguments to pass to saveRDS or saveRDS. If the first argument of saveRDS, that is, the object parameter, has an attribute called "RDS2.serialize", special serialization and deserialization will occur prior to writing to the file.

file

a connection or the name of the file where the R object is saved to or read from.

Details

The function behaves exactly the same as saveRDS for native R objects. However, if the object has an attribute called "RDS2.serialize", this will be used to serialize the object instead. Specifically, the attribute must be a list with keys "read" and "write" which must be functions that transform the object into a vanilla R object.

For example, suppose we have an object a <- list(x = 1, y = z), where z is an external pointer to a C structure. We could set the "RDS2.serialize" attribute as follows.

attr(a, "RDS2.serialize") <- list( read = function(obj) { obj$y <- raw_to_ptr(obj$y); obj }, write = function(obj) { obj$y <- ptr_to_raw(obj$y); obj } )

Here, raw_to_ptr and ptr_to_raw are helper functions that serialize and deserialize the C structure to an R object, such as a raw vector.

Value

For readRDS, an R object. For saveRDS, NULL, invisibly.

Note

The attribute "RDS2.serialize" will be serialized along with the object, so you must be careful that the parent environment chain of helper functions used in the read and write methods do not contain large objects. In general, it is better to use no helper functions (i.e., the read and write functions should be pure functions rather than closures, and you should set their environment(read) <- globalenv() explicitly.).

The mechanism provided by RDS2 is slightly different than the refhook argument to the base readRDS and saveRDS, since it encloses the serialization procedure within the serialized object. This allows for greater portability, since (if these functions are pure) the consumer of an RDS2-serialized object need only have the RDS2 package attached, rather than the function or library the refhook may be from.

Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
file <- tempfile()
native_obj <- list(x = 1)
saveRDS(native_obj, file)
stopifnot(identical(native_obj, readRDS(file)))

# We do not have any C structures to play with, but we will pretend
# by converting the string "pointer" to a raw vector.
nonnative_obj <- list(x = 1, y = "pointer")
attr(nonnative_obj, "RDS2.serialize") <- list(
  read  = function(obj) { obj$y <- rawToChar(obj$y); obj },
  write = function(obj) { obj$y <- charToRaw(obj$y); obj }
)
saveRDS(nonnative_obj, file)
without_attributes <- function(obj) { attr(obj, "RDS2.serialize") <- NULL; obj }
stopifnot(identical(list(x = 1, y = charToRaw("pointer")),
  without_attributes(base::readRDS(file))))
stopifnot(all.equal(nonnative_obj, readRDS(file)))
# Without RDS2, the vanilla object that was passed through the "write" method
# is stored in the file. We cannot load the object correctly unless RDS2
# is in the search path, so consumers of this RDS file should be careful.

# With RDS, the object is deserialized correctly.

robertzk/RDS2 documentation built on May 27, 2019, 10:33 a.m.