Some googledrive functions are built to naturally handle multiple files, while others operate on a single file.

Functions that expect a single file:

Functions that allow multiple files:

In general, the principle is: if there are multiple parameters that are likely to vary across multiple files, the function is designed to take a single input. In order to use these function with multiple inputs, use them together with your favorite approach for iteration in R. Below is a worked example, focusing on tools in the tidyverse, namely the map() functions in purrr.

Upload multiple files, then rename them

Scenario: we have multiple local files we want to upload into a folder on Drive. Then we regret their original names and want to rename them.

Load packages.

Upload

Use the example files that ship with googledrive.

local_files <- drive_examples_local()
local_files <- set_names(local_files, basename(local_files))
local_files
#>                                                                         chicken.csv 
#>     "/home/runner/work/_temp/Library/googledrive/extdata/example_files/chicken.csv" 
#>                                                                         chicken.jpg 
#>     "/home/runner/work/_temp/Library/googledrive/extdata/example_files/chicken.jpg" 
#>                                                                         chicken.pdf 
#>     "/home/runner/work/_temp/Library/googledrive/extdata/example_files/chicken.pdf" 
#>                                                                         chicken.txt 
#>     "/home/runner/work/_temp/Library/googledrive/extdata/example_files/chicken.txt" 
#>                                                                     imdb_latin1.csv 
#> "/home/runner/work/_temp/Library/googledrive/extdata/example_files/imdb_latin1.csv" 
#>                                                                        r_about.html 
#>    "/home/runner/work/_temp/Library/googledrive/extdata/example_files/r_about.html" 
#>                                                                          r_logo.jpg 
#>      "/home/runner/work/_temp/Library/googledrive/extdata/example_files/r_logo.jpg"

Create a folder on your Drive and upload all files into this folder by iterating over the local_files using purrr::map().

folder <- drive_mkdir("upload-into-me-article-demo")
#> Created Drive file:
#> • 'upload-into-me-article-demo' <id: 1mQU2Vz66VYb_1xb872BiXetv-MpsXiTK>
#> With MIME type:
#> • 'application/vnd.google-apps.folder'
with_drive_quiet(
  files <- map(local_files, ~ drive_upload(.x, path = folder))
)

First, let’s confirm that we uploaded the files into the new folder.

drive_ls(folder)
#> # A dribble: 7 × 3
#>   name            id                                drive_resource   
#>   <chr>           <drv_id>                          <list>           
#> 1 r_logo.jpg      1COju-7WYBXorEI-eweQXyt7QIzBkmXqT <named list [41]>
#> 2 r_about.html    1Pd9_1o_HwWSXnc3cQeaODOvAJcmLHraP <named list [40]>
#> 3 imdb_latin1.csv 1fXraVNr35far8y4SfnF7_YM0eUD0rzie <named list [39]>
#> 4 chicken.txt     1sNxuR6A0DAbeUo0zdBRlWabas1rjUWpJ <named list [40]>
#> 5 chicken.pdf     1ZGLT1IdAFGvDoQmq-pj_lNPrggu7Iw2y <named list [40]>
#> 6 chicken.jpg     1kZjLglzNmYTpvGnxPX416k0zfvuV4y6A <named list [41]>
#> 7 chicken.csv     1yuvVwQVYrXpRjZvFRivD-qPnBYJSQuhB <named list [39]>

Now let’s reflect on the files object returned by this operation. files is a list of dribbles, one per uploaded file.

str(files, max.level = 1)
#> List of 7
#>  $ chicken.csv    : dribble [1 × 3] (S3: dribble/tbl_df/tbl/data.frame)
#>  $ chicken.jpg    : dribble [1 × 3] (S3: dribble/tbl_df/tbl/data.frame)
#>  $ chicken.pdf    : dribble [1 × 3] (S3: dribble/tbl_df/tbl/data.frame)
#>  $ chicken.txt    : dribble [1 × 3] (S3: dribble/tbl_df/tbl/data.frame)
#>  $ imdb_latin1.csv: dribble [1 × 3] (S3: dribble/tbl_df/tbl/data.frame)
#>  $ r_about.html   : dribble [1 × 3] (S3: dribble/tbl_df/tbl/data.frame)
#>  $ r_logo.jpg     : dribble [1 × 3] (S3: dribble/tbl_df/tbl/data.frame)

This would be a favorable data structure if you’ve got more map()ing to do, as you’ll see below.

But what if not? You can always row bind individual dribbles into one big dribble yourself with, e.g., dplyr::bind_rows().

bind_rows(files)
#> # A dribble: 7 × 3
#>   name            id                                drive_resource   
#>   <chr>           <drv_id>                          <list>           
#> 1 chicken.csv     1yuvVwQVYrXpRjZvFRivD-qPnBYJSQuhB <named list [39]>
#> 2 chicken.jpg     1kZjLglzNmYTpvGnxPX416k0zfvuV4y6A <named list [41]>
#> 3 chicken.pdf     1ZGLT1IdAFGvDoQmq-pj_lNPrggu7Iw2y <named list [39]>
#> 4 chicken.txt     1sNxuR6A0DAbeUo0zdBRlWabas1rjUWpJ <named list [39]>
#> 5 imdb_latin1.csv 1fXraVNr35far8y4SfnF7_YM0eUD0rzie <named list [39]>
#> 6 r_about.html    1Pd9_1o_HwWSXnc3cQeaODOvAJcmLHraP <named list [39]>
#> 7 r_logo.jpg      1COju-7WYBXorEI-eweQXyt7QIzBkmXqT <named list [41]>

Below we show another way to finesse this by using a variant of purrr::map() that does this for us, namely map_dfr().

Rename

Imagine that we now wish these file names had a date prefix. First, form the new names. We use glue::glue() for string interpolation but you could also use paste(). Second, we map over two inputs: the list of dribbles from above and the vector of new names.

(new_names <- glue("{Sys.Date()}_{basename(local_files)}"))
#> 2021-09-24_chicken.csv
#> 2021-09-24_chicken.jpg
#> 2021-09-24_chicken.pdf
#> 2021-09-24_chicken.txt
#> 2021-09-24_imdb_latin1.csv
#> 2021-09-24_r_about.html
#> 2021-09-24_r_logo.jpg
files_dribble <- map2_dfr(files, new_names, drive_rename)
#> Original file:
#> • 'chicken.csv' <id: 1yuvVwQVYrXpRjZvFRivD-qPnBYJSQuhB>
#> Has been renamed:
#> • '2021-09-24_chicken.csv' <id: 1yuvVwQVYrXpRjZvFRivD-qPnBYJSQuhB>
#> Original file:
#> • 'chicken.jpg' <id: 1kZjLglzNmYTpvGnxPX416k0zfvuV4y6A>
#> Has been renamed:
#> • '2021-09-24_chicken.jpg' <id: 1kZjLglzNmYTpvGnxPX416k0zfvuV4y6A>
#> Original file:
#> • 'chicken.pdf' <id: 1ZGLT1IdAFGvDoQmq-pj_lNPrggu7Iw2y>
#> Has been renamed:
#> • '2021-09-24_chicken.pdf' <id: 1ZGLT1IdAFGvDoQmq-pj_lNPrggu7Iw2y>
#> Original file:
#> • 'chicken.txt' <id: 1sNxuR6A0DAbeUo0zdBRlWabas1rjUWpJ>
#> Has been renamed:
#> • '2021-09-24_chicken.txt' <id: 1sNxuR6A0DAbeUo0zdBRlWabas1rjUWpJ>
#> Original file:
#> • 'imdb_latin1.csv' <id: 1fXraVNr35far8y4SfnF7_YM0eUD0rzie>
#> Has been renamed:
#> • '2021-09-24_imdb_latin1.csv' <id: 1fXraVNr35far8y4SfnF7_YM0eUD0rzie>
#> Original file:
#> • 'r_about.html' <id: 1Pd9_1o_HwWSXnc3cQeaODOvAJcmLHraP>
#> Has been renamed:
#> • '2021-09-24_r_about.html' <id: 1Pd9_1o_HwWSXnc3cQeaODOvAJcmLHraP>
#> Original file:
#> • 'r_logo.jpg' <id: 1COju-7WYBXorEI-eweQXyt7QIzBkmXqT>
#> Has been renamed:
#> • '2021-09-24_r_logo.jpg' <id: 1COju-7WYBXorEI-eweQXyt7QIzBkmXqT>

We use purrr::map2_dfr() to work through files, the list of dribbles (= Drive files), and new_names, the vector of new names, and row bind the returned dribbles into a single dribble holding all files.

Let’s check on the contents of this folder again to confirm the new names:

drive_ls(folder)
#> # A dribble: 7 × 3
#>   name                       id                                drive_resource   
#>   <chr>                      <drv_id>                          <list>           
#> 1 2021-09-24_r_logo.jpg      1COju-7WYBXorEI-eweQXyt7QIzBkmXqT <named list [41]>
#> 2 2021-09-24_r_about.html    1Pd9_1o_HwWSXnc3cQeaODOvAJcmLHraP <named list [40]>
#> 3 2021-09-24_imdb_latin1.csv 1fXraVNr35far8y4SfnF7_YM0eUD0rzie <named list [39]>
#> 4 2021-09-24_chicken.txt     1sNxuR6A0DAbeUo0zdBRlWabas1rjUWpJ <named list [40]>
#> 5 2021-09-24_chicken.pdf     1ZGLT1IdAFGvDoQmq-pj_lNPrggu7Iw2y <named list [40]>
#> 6 2021-09-24_chicken.jpg     1kZjLglzNmYTpvGnxPX416k0zfvuV4y6A <named list [41]>
#> 7 2021-09-24_chicken.csv     1yuvVwQVYrXpRjZvFRivD-qPnBYJSQuhB <named list [39]>

Let’s confirm that, by using map2_df2() instead of map2(), we got a single dribble back, instead of a list of one-row dribbles:

files_dribble
#> # A dribble: 7 × 3
#>   name                       id                                drive_resource   
#>   <chr>                      <drv_id>                          <list>           
#> 1 2021-09-24_chicken.csv     1yuvVwQVYrXpRjZvFRivD-qPnBYJSQuhB <named list [39]>
#> 2 2021-09-24_chicken.jpg     1kZjLglzNmYTpvGnxPX416k0zfvuV4y6A <named list [41]>
#> 3 2021-09-24_chicken.pdf     1ZGLT1IdAFGvDoQmq-pj_lNPrggu7Iw2y <named list [40]>
#> 4 2021-09-24_chicken.txt     1sNxuR6A0DAbeUo0zdBRlWabas1rjUWpJ <named list [40]>
#> 5 2021-09-24_imdb_latin1.csv 1fXraVNr35far8y4SfnF7_YM0eUD0rzie <named list [39]>
#> 6 2021-09-24_r_about.html    1Pd9_1o_HwWSXnc3cQeaODOvAJcmLHraP <named list [40]>
#> 7 2021-09-24_r_logo.jpg      1COju-7WYBXorEI-eweQXyt7QIzBkmXqT <named list [41]>

What if you wanted to get a list back, because your downstream operations include yet more map()ing? Then you would use map2().

files_list <- map2(files, new_names, drive_rename)

Clean up

Our trashing function, drive_trash() is vectorized and can therefore operate on a multi-file dribble. We could trash these files like so:

drive_trash(files_dribble)

If you’re absolutely sure of yourself and happy to do something irreversible, you could truly delete these files with drive_rm(), which is also vectorized:

drive_rm(files_dribble)

Finally – and this is the code we will actually execute – the easiest way to delete these files is to delete their enclosing folder.

drive_rm(folder)
#> File deleted:
#> • 'upload-into-me-article-demo' <id: 1mQU2Vz66VYb_1xb872BiXetv-MpsXiTK>