尝试以交互方式加载由暂停的批处理脚本保存的数据文件时出错

Posted

技术标签:

【中文标题】尝试以交互方式加载由暂停的批处理脚本保存的数据文件时出错【英文标题】:Error when trying to interactively load data file saved by paused batch script 【发布时间】:2014-05-19 05:00:34 【问题描述】:

在调试和解决我的检索属性 (Can I access R data objects' attributes without fully loading objects from file?) 问题的过程中,根据此处关于 SO 的建议,我相应地从使用save()load() 切换到saveRDS()readRDS()

我的调查(通过非交互式调试打印)显示如下:

    在初始 saveRDS() 之后立即保存的对象包含有问题的属性;

    在脚本初始运行后执行的交互式 R 会话显示保存对象中属性的缺失

    上述发现解释了在下次运行脚本时未能检索到所述属性,我最初错误地将其归因于 save/loadsaveRDS/readRDS 行为。

为了手动确认在初始saveRDS 之后立即在持久对象中存在属性(保存在.rds 文件中),我决定暂停批处理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 文件确实已损坏(可能是由于我通过反复按Ctrl-C 来停止正在运行的批处理R 脚本的做法——我需要想出一些更“温和”的东西)。在找到更好的方法来停止正在运行的脚本后,我将尝试重现该场景并在此处报告。

更新 2:

从缓存目录中删除所有(可能已损坏的).rds 文件并按照上述场景(以交互方式加载 R 数据文件并暂停批处理 R 脚本)后,输出显示完全相同的错误消息强>和以前一样。在这一点上,我真的需要一个建议来弄清楚发生了什么。

UPADATE 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 变量的,但是代码保存了变量的名称

【问题讨论】:

您的示例(和更新)仍然完全无法重现! @mnel:抱歉,我认为只要查看这个相当简单的代码就可以看出问题所在。我将尝试提出一个可重现的示例。 【参考方案1】:

如果您使用saveRDS 保存某些内容,则等效的loading 函数为readRDS/ 如果您将save 对象放入RData 文件中,则应使用load 加载该对象。

readRDS 将允许您指定正在加载的对象的名称。

loadobjects 加载到.RData 文件中,它们将保留保存时使用的名称。

如果"../cache/SourceForge/ZGV2TGlua3M=.rds"是用saveRDS保存的,那么

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

将对象加载为whatever

对未以.RData 格式保存的文件运行load 将导致您发布的错误消息。

【讨论】:

非常感谢!我在脚本中使用了正确的函数对,但在交互式会话中完全忘记了这一点。我刚刚尝试过,readRDS(...) 确实有效,但readRDS(load(...)) 无效(导致相同的错误消息)。但是,readRDS() 的返回值包含了我打算保存的对象的名称,而不是预期的对象本身……相应地,大概保存的属性丢失了。 是的,这很有效!谢谢!您对为什么 readRDS() 返回对象的名称而不是对象本身有任何评论吗?请参阅我的 UPDATE 3 以及保存对象的代码。 @AleksandrBlekh - 发布一个可重现的示例 添加了可重现的示例(更新 4)。 将此作为一个单独的问题发布,并带有改进的可重复示例:***.com/questions/23739359/…。

以上是关于尝试以交互方式加载由暂停的批处理脚本保存的数据文件时出错的主要内容,如果未能解决你的问题,请参考以下文章

13Shell脚本—编写简单脚本

python import 以交互方式工作,但不是来自脚本

以代码的方式管理quartz定时任务的暂停重启删除添加等

python小脚本Yaml配置文件动态加载

python小脚本Yaml配置文件动态加载

在 AutoIt 中以编程方式暂停脚本?