2015-05-25 14 views
33

Ich habe ?connections in R gelesen und erfolgreich verwendet, aber ich verstehe wirklich nicht, was sie sind.Was genau ist eine Verbindung in R?

Ich bekomme, dass ich eine Datei herunterladen kann, lesen und schreiben eine komprimierte Datei, ... (das ist, verstehe ich, was das Ergebnis der Verwendung einer Verbindung (offen, Sachen, schließen), aber ich wirklich nicht verstehe, was sie eigentlich tun, warum musst du sie öffnen und schließen und so weiter).

Ich hoffe, dies wird mir auch helfen, zu verstehen, wie man sie effektiver nutzt (prinzipiell die Mechanismen verstehen, was passiert, damit ich effektiv debuggen kann, wenn etwas nicht funktioniert).

Antwort

57

Die Verbindungen wurden in R 1.2.0 eingeführt und von Brian Ripley in der ersten Ausgabe von R NEWS (jetzt The R Journal) von January 2001 (Seite 16-17) als abstrahierte Schnittstelle zu IO-Streams wie einer Datei beschrieben , URL, Socket oder Pipe. Im Jahr 2013 fügte Simon Urbanek eine Connections.h C-API hinzu, die es R-Paketen ermöglicht, benutzerdefinierte Verbindungstypen wie das curl-Paket zu implementieren.

Ein Merkmal der Verbindungen ist, dass Sie schrittweise Stücke von Daten vom/zum Anschluss lesen oder schreiben können mit den readBin, writeBin, readLines und writeLines Funktionen. Dies ermöglicht eine asynchrone Datenverarbeitung, beispielsweise wenn es um große Daten oder Netzwerkverbindungen geht:

Gleiches zum Schreiben, z.B. in einer Datei:

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

Öffnen die Verbindung als rb oder wb in binäre Daten (so genannte rohe Vektoren in R) lesen/schreiben:

# 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) 

Die pipe() Verbindung wird verwendet, um einen Systembefehl auszuführen und Pipe Text zu stdin oder von stdout wie Sie mit dem Operator | in einer Shell tun würde. Z.B. (Lässt Stick mit den curl Beispiele), können Sie die curl Kommandozeilenprogramm und Rohr der Ausgang R laufen:

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) 

Einige Aspekte der Verbindungen sind etwas verwirrend: inkrementell lesen/schreiben Daten explizit zu müssen open() und close() die Verbindung. readLines und writeLines öffnen und schließen (aber nicht zerstören!) Automatisch eine ungeöffnete Verbindung. Als Ergebnis wird das folgende Beispiel die ersten 10 Zeilen über gelesen und immer wieder was nicht sehr nützlich ist:

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) 

Eine andere gotcha ist, dass die C-API kann sowohl in der Nähe und zerstören eine Verbindung, aber R macht nur eine Funktion verfügbar, die close()genannt wird, die eigentlich zerstören bedeutet. Nach dem Aufruf von close() auf einer Verbindung ist es zerstört und völlig nutzlos.

Um Stream-Prozessdaten bilden eine Verbindung möchten Sie so ein Muster verwenden:

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) 
    } 
} 

Das jsonlite Paket stark auf Verbindungen angewiesen importieren/exportieren ndjson Daten:

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

Die Streaming (standardmäßig 1000 Zeilen zu einer Zeit) macht es schnell und Speicher effizient:

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

schließlich ein nettes Feature über Verbindungen ist, dass der Garbage Collector sie automatisch geschlossen werden, wenn Sie dies tun vergessen, mit einer lästigen Warnung:

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

Epische Antwort. Sprechen Sie die Frage des OP sogar marginal an. –