Question Qu'est-ce qu'une connexion dans R?


J'ai lu et utilisé avec succès ?connections dans R mais je ne comprends vraiment pas ce qu'ils sont.

Je comprends que je peux télécharger un fichier, lire et écrire un fichier compressé, ... (c'est que je comprends ce que le résultat de l'utilisation d'une conection (open, do stuff, close) mais je ne comprends vraiment pas ce qu'ils font réellement, pourquoi vous devez les ouvrir, etc.).

J'espère que cela m'aidera également à comprendre comment les utiliser plus efficacement (comprendre principalement la mécanique de ce qui se passe afin que je puisse efficacement déboguer quand quelque chose ne fonctionne pas).


35
2018-05-25 20:54


origine


Réponses:


Les connexions ont été introduites dans R 1.2.0 et décrites par Brian Ripley dans le premier numéro de R NEWS (maintenant appelé The R Journal) de Janvier 2001 (page 16-17) en tant qu'interface abstraite vers des flux IO tels qu'un fichier, une URL, un socket ou un tube. En 2013, Simon Urbanek a ajouté un Connections.h C API qui permet aux packages R d'implémenter des types de connexion personnalisés, tels que le boucle paquet.

L'une des caractéristiques des connexions est que vous pouvez lire ou écrire de manière incrémentielle des éléments de données depuis / vers la connexion en utilisant le readBin, writeBin, readLines et writeLines les fonctions. Cela permet un traitement de données asynchrone, par exemple lorsque vous traitez des données volumineuses ou des connexions réseau:

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

Idem pour l'écriture, par ex. à un fichier:

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

Ouvrez la connexion en tant que rb ou wb pour lire / écrire des données binaires (appelées vecteurs bruts dans 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)

le pipe() la connexion est utilisée pour exécuter une commande système et un texte de conduite stdin ou de stdout comme vous le feriez avec le | opérateur dans un shell. Par exemple. (laisse les exemples de curl), vous pouvez lancer le curl programme de ligne de commande et diriger la sortie vers 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)

Certains aspects des connexions sont un peu déroutants: pour lire / écrire de manière incrémentielle les données dont vous avez besoin explicitement open() et close() la connexion. cependant, readLines et writeLines ouvrir et fermer automatiquement (mais pas détruire!) une connexion non ouverte. Par conséquent, l'exemple ci-dessous va lire les 10 premières lignes encore et encore, ce qui n'est pas très utile:

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)

Un autre piège est que l’API C peut à la fois Fermer et détruire une connexion, mais R n'expose qu'une fonction appelée close()  ce qui signifie réellement détruire. Après avoir appelé close() sur une connexion, il est détruit et complètement inutile.

Pour traiter en continu les données d'une connexion, vous souhaitez utiliser un modèle comme celui-ci:

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

le jsonlite le package repose fortement sur les connexions à l'import / export ndjson Les données:

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

Le streaming (par défaut 1000 lignes à la fois) le rend rapide et efficace en termes de mémoire:

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

Enfin, une fonctionnalité intéressante sur les connexions est que le garbage collector les ferme automatiquement si vous oubliez de le faire, avec un avertissement ennuyeux:

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

63
2018-05-25 21:25