如何将在线源的shapefile文件直接读取到R环境中?
问题背景
我目前在探索如何将存储在在线仓库、文件夹或URL路径下的shapefile(.shp格式)直接加载到R全局环境,最终目标是结合ggplot2的geom_sf函数绘制空间可视化图形。
最初我用Google Drive存储相关文件,但更希望找到通用方案,适配所有持有有效访问权限、可通过URL定位的文件存储路径。目前我已经尝试了三类实现方式,前两类都是先把Google Drive里存shapefile的源文件夹压缩为zip包,再通过不同方式下载、解压,以下是基于小型测试shapefile编写的可复现代码:
- 第一种方法:调用
utils::download.file()获取压缩文件夹,再分别通过base::system('unzip..')或zip::unzip()解压,参考社区内下载ONS郡级shapefile的相关思路,对应代码如下:
# 若不存在data文件夹则新建 if(!dir.exists('data')) dir.create('data') # 下载压缩文件/文件夹 download.file("https://drive.google.com/file/d/1BYTCT_VL8EummlAsH1xWCd5rC4bZHDMh/view?usp=sharing", destfile = "data/test_shp.zip") # 用内置unzip函数解压(运行失败) unzip(zipfile = "data/test_shp.zip", exdir = "data/test_shp", junkpaths = TRUE) # 用系统unzip命令解压(同样运行失败) system("unzip data/test_shp.zip")
运行上述代码会返回两类报错:
Warning message:
In unzip(zipfile = "data/test_shp.zip", exdir = "data/test_shp", :
error 1 in extracting from zip file
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
unzip: cannot find zipfile directory in one of data/test_shp.zip or
data/test_shp.zip.zip, and cannot find data/test_shp.zip.ZIP, period.
我在R环境外也无法手动解压下载得到的文件,因此判断问题出在download.file()的下载步骤,拿到的文件并非有效zip压缩包。
- 第二种方法:用googledrive包实现读取,对应代码如下:
# 若不存在data文件夹则新建 if(!dir.exists('data')) dir.create('data') # 指定Google Drive文件链接 test_shp = drive_get(as_id("https://drive.google.com/file/d/1BYTCT_VL8EummlAsH1xWCd5rC4bZHDMh/view?usp=sharing")) # 下载压缩文件夹 drive_download(test_shp, path = "data/test_shp.zip") # 解压文件夹 zip::unzip(zipfile = "data/test_shp.zip", exdir = "data/test_shp", junkpaths = TRUE) # 读取test.shp文件 test_shp <- read_sf("data/test_shp/test.shp")
这个方法可以成功运行,但属于临时变通方案:需要手动压缩文件、下载、解压,再调用独立函数(比如sf::read_sf或st_read)把数据读入全局环境;同时因为依赖googledrive包,只能读取Google Drive存储的文件,无法适配OneDrive、DropBox等其他平台的URL。
- 第三种方法:我还尝试直接对文件夹URL调用
sf::read_sf、st_read、fastshp::read.shp读取,结果全部失败。
目前想咨询两个问题:
- 是否存在可以将在线存储的shapefile直接读入R的成熟工作流?
- 如果不存在这类直接读取的方案,有没有技巧可以把上述第二种方案拓展,适配Google Drive之外的存储平台?
补充说明:因为rgdal包即将永久退役,我刻意排除了所有依赖rgdal的实现方案,希望找到具备长期兼容性的方法。
解决方案
第一种方法失败的核心原因
用download.file()抓取Google Drive普通分享链接拿到的不是实际zip文件,是Google Drive的病毒扫描中转页面HTML,所以解压必然报错。所有云盘平台的普通分享链接默认都跳转到预览/中转页面,不是文件直链,直接下载拿到的都是网页文件,不是原始数据。
通用跨平台工作流(无rgdal依赖,长期兼容)
核心逻辑是先拿到文件的直链URL,再通过临时文件中转下载、自动解压读取,全程不需要手动操作本地文件,适配所有支持直链的存储平台,不需要依赖各个云盘的专属SDK包。
第一步:获取各平台文件直链
不同云盘的分享链接转直链规则固定,不需要额外安装工具包:
- Google Drive:提取分享链接里的文件ID,拼到固定路径
https://drive.google.com/uc?export=download&id=后面即可,比如测试文件的直链就是对应ID拼接后的地址 - Dropbox:将分享链接末尾的
dl=0改成dl=1即为直链 - OneDrive:在分享链接末尾加
&download=1即为直链 - 普通HTTP文件服务器、代码仓库的原始文件链接本身就是直链,不需要修改
第二步:封装通用读取函数
用临时文件承接下载的zip包,自动识别压缩包里的.shp文件读取,读完自动清理临时文件,不需要手动建文件夹、解压、删文件,直接返回sf对象到全局环境:
library(sf) library(httr) read_online_shp <- function(url, ...) { # 创建临时文件、临时文件夹,运行完自动清理 temp_zip <- tempfile(fileext = ".zip") temp_dir <- tempdir() on.exit(unlink(c(temp_zip, temp_dir), recursive = TRUE)) # 下载文件,自动处理网页跳转、大文件确认 GET( url, write_disk(temp_zip, overwrite = TRUE), config(followlocation = TRUE), user_agent("Mozilla/5.0") ) # 解压压缩包,自动定位shp文件 unzip(temp_zip, exdir = temp_dir, junkpaths = TRUE) shp_path <- list.files(temp_dir, pattern = "\\.shp$", full.names = TRUE)[1] # 读取并返回sf对象 read_sf(shp_path, ...) }
第三步:直接调用读取
不管哪个平台的直链,直接传进函数就能拿到sf对象,可直接配合geom_sf画图,比如读取测试文件仅需一行代码:
test_shp <- read_online_shp("对应文件的直链地址") # 直接绘图 library(ggplot2) ggplot() + geom_sf(data = test_shp)
补充说明
- 如果是需要权限的私有文件,在
GET()请求里加对应的认证头即可,比如平台对应的API访问令牌,不需要修改核心逻辑 - 如果shapefile是单独上传、没有打包成zip,只要把.shx、.dbf、.prj这些配套文件的直链都下载到同一个临时文件夹,再读取.shp即可,逻辑和读本地文件完全一致
- 不要尝试直接给
read_sf传非直链的普通分享URL,sf底层读文件需要随机访问文件字节,云盘预览页不支持这个操作,必然失败
内容的提问来源于stack exchange,提问作者bjcresswell

