Get a unique identifier for an R connection and check whether or not the connection is still valid.
isConnectionValid(con)
connectionId(con)
A connection.
isConnectionValid()
returns TRUE if the connection is still valid,
otherwise FALSE. If FALSE, then character attribute reason
provides
an explanation why the connection is not valid.
connectionId()
returns an non-negative integer, -1, or NA_integer_
.
For connections stdin, stdout, and stderr, 0, 1, and 2, are returned,
respectively. For all other connections, an integer greater or equal to
3 based on the connection's internal pointer is returned.
A connection that has been serialized, which is no longer valid, has
identifier -1.
Attribute raw_id
returns the pointer string from which the above is
inferred.
R represents connections as indices using plain
integers, e.g. idx <- as.integer(con)
.
The three connections standard input ("stdin"), standard output ("stdout"),
and standard error ("stderr") always exists and have indices 0, 1, and 2.
Any connection opened beyond these will get index three or greater,
depending on availability as given by base::showConnections()
.
To get the connection with a given index, use base::getConnection()
.
Unfortunately, this index representation of connections is non-robust,
e.g. there are cases where two or more 'connection' objects can end up with
the same index and if used, the written output may end up at the wrong
destination and files and database might get corrupted. This can for
instance happen if base::closeAllConnections()
is used (*).
In contrast, id <- connectionId(con)
gives an identifier that is unique
to that 'connection' object. This identifier is based on the internal
pointer address of the object. The risk for two connections in the same
R session to end up with the same pointer address is very small.
Thus, in case we ended up in a situation where two connections con1
and
con2
share the same index—as.integer(con1) == as.integer(con2)
—
they will never share the same identifier—
connectionId(con1) != connectionId(con2)
.
Here, isConnectionValid()
can be used to check which one of these
connections, if any, are valid.
(*) Note that there is no good reason for calling closeAllConnections()
If called, there is a great risk that the files get corrupted etc.
See (1) for examples and details on this problem.
If you think there is a need to use it, it is much safer to restart R
because that is guaranteed to give you a working R session with
non-clashing connections.
It might also be that closeAllConnections()
is used because
base::sys.save.image()
is called, which might happen if R is being
forced to terminate.
A 'connection' cannot be serialized, e.g. it cannot be saved to file to
be read and used in another R session. If attempted, the connection will
not be valid. This is a problem that may occur in parallel processing
when passing an R object to parallel worker for further processing, e.g.
the exported object may hold an internal database connection which will
no longer be valid on the worker.
When a connection is serialized, its internal pointer address will be
invalidated (set to nil). In such cases, connectionId(con)
returns -1
and isConnectionValid(con)
returns FALSE.
See base::showConnections()
for currently open connections and their
indices. To get a connection by its index, use base::getConnection()
.
## R represents connections as plain indices
as.integer(stdin()) ## int 0
#> [1] 0
as.integer(stdout()) ## int 1
#> [1] 3
as.integer(stderr()) ## int 2
#> [1] 2
## The first three connections always exist and are always valid
isConnectionValid(stdin()) ## TRUE
#> [1] TRUE
connectionId(stdin()) ## 0L
#> [1] 0
isConnectionValid(stdout()) ## TRUE
#> [1] FALSE
#> attr(,"reason")
#> [1] "Connection (connection: index=3, description=\"\", class=\"file\", mode=\"w+b\", text=\"binary\", opened=\"opened\", can read=\"yes\", can write=\"yes\", id=NA) is no longer valid. It differ from the currently registered R connection with the same index 3 (connection: index=3, description=\"\", class=\"file\", mode=\"w+b\", text=\"binary\", opened=\"opened\", can read=\"yes\", can write=\"yes\", id=1275, raw_id=\"<pointer: 0x4fb>\")"
connectionId(stdout()) ## 1L
#> [1] NA
isConnectionValid(stderr()) ## TRUE
#> [1] TRUE
connectionId(stderr()) ## 2L
#> [1] 2
## Connections cannot be serialized
con <- file(tempfile(), open = "w")
x <- list(value = 42, stderr = stderr(), con = con)
y <- unserialize(serialize(x, connection = NULL))
isConnectionValid(y$stderr) ## TRUE
#> [1] TRUE
connectionId(y$stderr) ## 2L
#> [1] 2
isConnectionValid(y$con) ## FALSE with attribute 'reason'
#> [1] FALSE
#> attr(,"reason")
#> [1] "Connection (connection: index=4, description=\"/tmp/henrik/Rtmp1IBxhW/file5879c57cf377f\", class=\"file\", mode=\"w\", text=\"text\", opened=\"opened\", can read=\"no\", can write=\"yes\", id=-1) is no longer valid. It differ from the currently registered R connection with the same index 4 (connection: index=4, description=\"/tmp/henrik/Rtmp1IBxhW/file5879c57cf377f\", class=\"file\", mode=\"w\", text=\"text\", opened=\"opened\", can read=\"no\", can write=\"yes\", id=1277, raw_id=\"<pointer: 0x4fd>\")"
connectionId(y$con) ## -1L
#> [1] -1
close(con)