R中的连接究竟是什么?

时间:2015-05-25 20:54:24

标签: r connection

我已经阅读并在R中成功使用?connections但我真的不明白它们是什么。

我知道我可以下载文件,读取和写入压缩文件,...(我知道使用连接的结果是什么(打开,做东西,关闭)但我真的不喜欢了解他们实际做了什么,为什么你必须打开和关闭它们等等)。

我希望这也能帮助我理解如何更有效地使用它们(主要是理解正在发生的事情的机制,以便在有些事情不能正常工作时我能有效地进行调试)。

1 个答案:

答案 0 :(得分:67)

连接在R 1.2.0中引入,并由Brian Ripley在第一期“新闻”(现称为The R Journal)January 2001(第16-17页)中描述为IO流的抽象接口,如作为文件,URL,套接字或管道。 2013年,Simon Urbanek添加了Connections.h C API,使R包能够实现自定义连接类型,例如curl包。

连接的一个特性是,您可以使用readBinwriteBinreadLineswriteLines函数从连接中逐步读取或写入数据。这允许异步数据处理,例如在处理大数据或网络连接时:

# Read the first 30 lines, 10 lines at a time
con <- url("http://jeroen.github.io/data/diamonds.json") 
open(con, "r")
data1 <- readLines(con, n = 10)
data2 <- readLines(con, n = 10)
data3 <- readLines(con, n = 10)
close(con)

写作相同,例如到文件:

tmp <- file(tempfile())
open(tmp, "w")
writeLines("A line", tmp)
writeLines("Another line", tmp)
close(tmp)

rbwb打开连接以读取/写入二进制数据(在R中称为原始向量):

# Read the first 3000 bytes, 1000 bytes at a time
con <- url("http://jeroen.github.io/data/diamonds.json") 
open(con, "rb")
data1 <- readBin(con, raw(), n = 1000)
data2 <- readBin(con, raw(), n = 1000)
data3 <- readBin(con, raw(), n = 1000)
close(con)

pipe()连接用于运行系统命令和管道文本到stdinstdout,就像在shell中使用|运算符一样。例如。 (让我们坚持使用curl示例),您可以运行curl命令行程序并将输出传递给R:

con <- pipe("curl -H 'Accept: application/json' https://jeroen.github.io/data/diamonds.json")
open(con, "r")
data1 <- readLines(con, n = 10)
data2 <- readLines(con, n = 10)
data3 <- readLines(con, n = 10)

连接的某些方面有点令人困惑:要逐步读取/写入您需要明确open()close()连接的数据。但是,readLineswriteLines会自动打开和关闭(但不会销毁!)未打开的连接。因此,下面的示例将一遍又一遍地读取前10行,这不是很有用:

con <- url("http://jeroen.github.io/data/diamonds.json") 
data1 <- readLines(con, n = 10)
data2 <- readLines(con, n = 10)
data3 <- readLines(con, n = 10)
identical(data1, data2)

另一个问题是C API可以关闭销毁一个连接,但R只暴露了一个名为close() 的函数,这实际上意味着破坏即可。在连接上调用close()后,它被销毁并且完全没用。

要从您想要使用如下模式的连接中流式处理数据:

stream <- function(){
  con <- url("http://jeroen.github.io/data/diamonds.json")
  open(con, "r")
  on.exit(close(con))
  while(length(txt <- readLines(con, n = 10))){
    some_callback(txt)
  } 
}

jsonlite程序包在很大程度上依赖于导入/导出ndjson数据的连接:

library(jsonlite)
library(curl)
diamonds <- stream_in(curl("https://jeroen.github.io/data/diamonds.json"))

流式传输(默认情况下,每次1000行)使其快速且内存效率高:

library(nycflights13)
stream_out(flights, file(tmp <- tempfile()))
flights2 <- stream_in(file(tmp))
all.equal(flights2, as.data.frame(flights))

最后关于连接的一个很好的功能是,如果你忘了这么做,垃圾收集器会自动关闭它们,并带有恼人的警告:

con <- file(system.file("DESCRIPTION"), open = "r")
rm(con)
gc()