问题
I have some large geoTIFFs, now I want to convert them to ASCII files, after doing some searches, I write these codes:
library(raster)
f <- list.files("inputFolder", pattern = "*.tif", full.names = TRUE)
r <- lapply(f, raster)
a <- lapply(r, writeRaster, filename = "output", format = "ascii")
What confused me is that how can I name the output files respectively, according to its original names?
I tried:
a <- lapply(r, writeRaster, filename = "outputFolder" + f, format = "ascii")
But I received error:
non-numeric argument to binary operator
Then I tried:
a <- lapply(r, writeRaster, filename = paste0(f, ".asc"), format = "ascii")
But I received:
Error in file(filename, "w") : invalid 'description' argument In addition: Warning messages: 1: In if (filename == "") { : the condition has length > 1 and only the first element will be used 2: In if (!file.exists(dirname(filename))) { : the condition has length > 1 and only the first element will be used 3: In if (toupper(x@file@name) == toupper(filename)) { : the condition has length > 1 and only the first element will be used 4: In if (trim(filename) == "") { : the condition has length > 1 and only the first element will be used 5: In if (!file.exists(dirname(filename))) { : the condition has length > 1 and only the first element will be used 6: In if (filename == "") { : the condition has length > 1 and only the first element will be used 7: In if (!overwrite & file.exists(filename)) { : the condition has length > 1 and only the first element will be used
回答1:
I think you were basically nearly there, with two corrections:
First, you're calling writeRaster
for its side effects (i.e. its ability to write a file to your filesystem) so you don't need to assign the output of your lapply()
loop to an object. So, removing a <-
we have:
lapply(r, writeRaster, filename = paste0(f, ".asc"), format = "ascii")
Next, the filename
argument won't loop through f
in this way. You have two options, of which the simplest is probably to pass the @file@name
slot of r
to the filename
argument using an anonymous function:
lapply(r, function(x) {
writeRaster(x, filename = x@file@name, format = "ascii", overwrite = TRUE)
})
Your other option would be to loop through r
and f
in parallel like you can in python with for r, f in...
, which can be done with purrr
:
library("purrr")
walk2(r, f, function(x, y) {
writeRaster(x = x, filename = y, format = "ascii")
})
Here we're using walk2()
rather than map2()
because we need to call the function for side effects. This loops through r
and f
together so you can pass one to be the object to write, and one to be the filename.
Edit: here's the code I use to reproduce the problem
library("raster")
tmp_dir = tempdir()
tmp = tempfile(tmpdir = tmp_dir, fileext = ".zip")
download.file(
"http://biogeo.ucdavis.edu/data/climate/cmip5/10m/cc26bi50.zip",
destfile = tmp
)
unzip(tmp, exdir = tmp_dir)
f = list.files(tmp_dir, pattern = ".tif$", full.names = TRUE)
r = lapply(f, raster)
# Solution one
lapply(r, function(x) {
writeRaster(x, filename = x@file@name, format = "ascii", overwrite = TRUE)
})
# solution two
library("purrr")
walk2(r, f, function(x, y) {
writeRaster(x = x, filename = y, format = "ascii")
})
回答2:
To test how to do this with small files:
library(raster)
s <- stack(system.file("external/rlogo.grd", package="raster"))
writeRaster(s, file='testtif', format='GTiff', bylayer=T, overwrite=T)
f <- list.files(pattern="testtif_..tif")
Now you can use f
with Phil's nice examples. You can also combine all in one step lapply:
f <- list.files("inputFolder", pattern = "*.tif", full.names = TRUE)
r <- lapply(f, function(i) { writeRaster(raster(i), filename=extension(i, '.asc'), overwrite=TRUE)} )
But if you have trouble with lapply, write a loop (it is fine!):
for (i in 1:length(f)) {
r <- raster(f[i])
ff <- extension(f[i], '.asc')
writeRaster(r, ff)
}
Or like this
for (file in f) {
r <- raster(file)
ff <- extension(file, '.asc')
writeRaster(r, ff)
}
来源:https://stackoverflow.com/questions/47591678/how-to-batch-process-geotiffs-in-r-with-lapply