Ошибка при попытке интерактивно загрузить файл данных, сохраненный приостановленным пакетным скриптом

В процессе отладки и решения моей проблемы с получением атрибутов (Могу ли я получить доступ к атрибутам объектов данных R без полной загрузки объектов из файла?), основываясь на совете здесь, посвященном SO, я переключился с использования save() и load() на saveRDS() и readRDS() соответственно.

Мое исследование (через неинтерактивную отладочную печать) показало следующее:

  1. сразу после начального saveRDS() сохраненный объект содержит рассматриваемый атрибут;

  2. интерактивный R-сеанс, выполняемый после первоначального запуска скрипта, показывает отсутствие атрибута у сохраненного объекта;

  3. предыдущие результаты выше объясняют невозможность получения указанного атрибута во время следующего запуска скрипта, который я изначально неправильно приписал поведению save/load и saveRDS/readRDS.

Чтобы вручную подтвердить наличие атрибута в постоянном объекте (сохраненном в файле .rds) сразу после исходного saveRDS, я решил приостановить выполнение пакетного R-скрипта. в одном окне терминала с использованием scan (readLine не работает для этого в пакетных сценариях R):

if (DEBUG) {
  cat("Press [Enter] to continue")
  key <- scan("stdin", character(), n=1)
}

а в другом окне терминала проверить сохраненный объект с помощью интерактивного сеанса R.

Однако, когда после ожидаемой остановки пакетного сценария загрузка сохраненного объекта из файла .rds в интерактивном сеансе не удалась со следующим сообщением:

> load("../cache/SourceForge/ZGV2TGlua3M=.rds")
Error: bad restore file magic number (file may be corrupted) -- no data loaded
In addition: Warning message:
file ‘ZGV2TGlua3M=.rds’ has magic number 'X'
  Use of save versions prior to 2 is deprecated

Следующий вывод описывает мою среду R на момент расследования:

> sessionInfo()
R version 3.0.2 (2013-09-25)
Platform: x86_64-pc-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C
 [9] LC_ADDRESS=C               LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

Единственное приемлемое для меня объяснение состоит в том, что пакетный сеанс (и, в частности, пауза через scan) каким-то образом блокирует или изменяет среду, что делает невозможным правильный доступ к объектам R из интерактивного сеанса. Возможно, существуют и другие возможные причины такой ситуации. Буду очень признателен за любую помощь или совет по решению этой проблемы!

ОБНОВИТЬ:

Убив процесс пакетного R-скрипта (который после scan перестал отвечать), я снова попытался вручную загрузить файл .rds, ожидая успеха из-за отсутствия паузы в пакетном скрипте. Однако, к моему удивлению, меня встретило точно такое же сообщение об ошибке. Это заставляет меня думать, что файл .rds действительно поврежден (возможно, из-за моей практики остановки работающего пакетного R-скрипта путем многократного нажатия Ctrl-C - мне нужно будет придумать что-то более «мягкое»). Найдя лучший способ остановить запущенный скрипт, я попытаюсь воспроизвести сценарий и сообщить об этом здесь.

ОБНОВЛЕНИЕ 2:

После удаления всех (потенциально поврежденных) файлов .rds из каталога кеша и следования описанному выше сценарию (загрузка файла данных R в интерактивном режиме с приостановленным пакетным сценарием R) на выходе появилось точно то же сообщение об ошибке, что и раньше. На данный момент, мне действительно нужен совет, чтобы выяснить, что происходит.

ОБНОВЛЕНИЕ 3 (сохранение объекта):

assign(dataName, srdaGetData())
data <- as.name(dataName)

# save hash of the request's SQL query as data object's attribute,
# so that we can detect when configuration contains modified query
attr(data, "SQL") <- base64(request)

# save current data frame to RDS file
saveRDS(data, rdataFile)

ОБНОВЛЕНИЕ 4 (воспроизводимый пример):

library(RCurl)

info <- "Important data"
request <- "SELECT info FROM topSecret"
dataName <- "sf.data.devLinks"
rdataFile <- "/tmp/testAttr.rds"

getData <- function() {
  return (info)
}

requestDigest <- base64(request)

# check if the archive file has already been processed
message("\nProcessing request \"", request, "\" ...\n")

# read back the object with the attribute
if (file.exists(rdataFile)) {
  # now check if request's SQL query hasn't been modified
  data <- readRDS(rdataFile)
  message("Retrieved object '", as.name(data), "', containing:\n")
  message(toString(data))

  requestAttrib <- attr(data, "SQL", exact = TRUE)
  message("\nObject '", data, "' contains attribute:\n\"",
                 base64(requestAttrib), "\"\n")

  if (identical(requestDigest, requestAttrib)) {
    message("Processing skipped: RDS file is up-to-date.\n")
    stop()
  }
  rm(data)
}

message("Saving results of request \"",
        request, "\" as R data object ...\n")

assign(dataName, getData())
data <- as.name(dataName)

# save hash of the request's SQL query as data object's attribute,
# so that we can detect when configuration contains modified query
attr(data, "SQL") <- base64(request)

# save current data frame to RDS file
saveRDS(data, rdataFile)

Я ожидаю, что значение переменной dataName будет сохранено, однако код сохраняет имя переменной.


person Aleksandr Blekh    schedule 19.05.2014    source источник
comment
Ваш пример (и обновления) остаются полностью невоспроизводимыми!   -  person mnel    schedule 19.05.2014
comment
@mnel: Извините, я думал, что проблему можно увидеть, просто взглянув на этот довольно простой код. Я постараюсь привести воспроизводимый пример.   -  person Aleksandr Blekh    schedule 19.05.2014


Ответы (1)


Если вы сохраняете что-то с помощью saveRDS, эквивалентной функцией loading будет readRDS/. Если вы save объект в файле RData, вы должны использовать load для загрузки объекта.

readRDS позволит указать имя загружаемого объекта.

load загружает objects в файл .RData, и они сохраняют имена, под которыми были сохранены.

Если "../cache/SourceForge/ZGV2TGlua3M=.rds" было сохранено с помощью saveRDS, то

whatever <- readRDS("../cache/SourceForge/ZGV2TGlua3M=.rds")

загрузит объект как whatever

Запуск load для файла, не сохраненного в формате .RData, приведет к опубликованному вами сообщению об ошибке.

person mnel    schedule 19.05.2014
comment
Большое тебе спасибо! Я использую правильные пары функций в скрипте, но совершенно забыл об этом для интерактивного сеанса. Я только что попробовал, и readRDS(...) действительно работает, а readRDS(load(...)) — нет (приводит к тому же сообщению об ошибке). Однако возвращаемое значение readRDS() содержит имя объекта, который я намеревался сохранить, но не сам ожидаемый объект... Соответственно, предположительно сохраненный атрибут теряется. - person Aleksandr Blekh; 19.05.2014
comment
Да, это работало! Спасибо! Есть ли у вас какие-либо комментарии о том, почему readRDS() возвращает имя объекта, а не сам объект. Пожалуйста, смотрите мое ОБНОВЛЕНИЕ 3 с моим кодом сохранения объекта. - person Aleksandr Blekh; 19.05.2014
comment
@AleksandrBlekh - опубликуйте воспроизводимый пример - person mnel; 19.05.2014
comment
Добавлен воспроизводимый пример (ОБНОВЛЕНИЕ 4). - person Aleksandr Blekh; 19.05.2014
comment
Опубликовал это как отдельный вопрос с улучшенным воспроизводимым примером: name" title="как постоянно хранить значение объекта вместо его имени"> stackoverflow.com/questions/23739359/. - person Aleksandr Blekh; 19.05.2014