我正在尝试将已定义目录的所有文件夹和文件名读取到嵌套列表中,该列表将与顶层上的文件夹数一样长,然后每个列表元素具有与子文件中一样多的元素-directory(如果它是一个文件夹)等等,直到只有文件而没有其他文件夹的级别。
我的用例是我的iTunes Music文件夹:
m <- "/Users/User/Music/iTunes/iTunes Media/Music" # set the path to the library folder
x <- list.files(m, recursive = FALSE) # get all artists names (folder names on top level)
# read all Albums and title of each song per album
lst <- setNames(lapply(paste(m, x, sep = "/"), list.files, recursive = T), x)
lst
中每个元素的结构现在是:
#$`The Kooks` # artist name "The Kooks"
# [1] "Inside In Inside Out/01 Seaside.mp3" # album name "Inside In Inside Out", title "01 Seaside.mp3"
# [2] "Inside In Inside Out/02 See The World.mp3"
#...
#[16] "Konk/01 See The Sun.mp3" # second album of The Kooks
#[17] "Konk/02 Always Where I Need To Be.mp3"
我正在尝试做的是使每个艺术家的条目嵌套列表,因此在示例中会有列表元素$TheKooks
,其中包含2个(子)列表(每个专辑1个) ):$Inside In Inside Out
和$Konk
,每个专辑列表中都有一个标题名称向量(没有专辑名称)。
我无法在SO上找到正确的答案并尝试(未成功),等等:
list.files(m, recursive = TRUE)
和
lapply(lst, function(l) {
strsplit(l, "/")
})
如何正确地做到这一点?
P.S:
答案 0 :(得分:3)
假设您的目录结构始终为artist/album/songs
,此解决方案应该有效。如果某些目录更深(或更深),你将得不到你想要的东西。
首先,我获取目录列表(即艺术家列表):
artists <- list.dirs(path=m,recursive=FALSE,full.names=FALSE)
然后我创建了嵌套列表:
lapply(artists,function(dir) {
albums <- list.dirs(path=paste0(m,"/",dir),recursive=FALSE,full.names=FALSE)
album.list <-
lapply(albums,function(dir2) {
list.files(path=paste0(m,"/",dir,"/",dir2))
})
names(album.list) <- albums
album.list
})
最后,我将名单列为最高级别:
names(music.list) <- artists
专辑级别与艺术家级别相同:我获取目录(对应于专辑),然后列出内部文件(对应于歌曲),最后,我按专辑名称命名列表元素。
修改强> 正如docendo discimus指出的那样,上述解决方案并不普遍。以下递归解决方案应该以更优雅的方式完成工作:
rfl <- function(path) {
folders <- list.dirs(path,recursive=FALSE,full.names=FALSE)
if (length(folders)==0) list.files(path)
else {
sublist <- lapply(paste0(path,"/",folders),rfl)
setNames(sublist,folders)
}
}
rfl(m)
它仍然不完全通用:只要文件夹包含子文件夹,算法就会进入这些文件夹,而不用存储可能同样存在于列表中相同深度的文件。
答案 1 :(得分:3)
以下函数标识目录中的文件和文件夹。然后它会为每个标识的文件夹再次调用自己,创建一个列表,其中包含找到的所有文件和子文件夹。
fileFun <- function(theDir) {
## Look for files (directories included for now)
allFiles <- list.files(theDir, no.. = TRUE)
## Look for directory names
allDirs <- list.dirs(theDir, full.names = FALSE, recursive = FALSE)
## If there are any directories,
if(length(allDirs)) {
## then call this function again
moreFiles <- lapply(file.path(theDir, allDirs), fileFun)
## Set names for the new list
names(moreFiles) <- allDirs
## Determine files found, excluding directory names
outFiles <- allFiles[!allFiles %in% allDirs]
## Combine appropriate results for current list
if(length(outFiles)) {
allFiles <- c(outFiles, moreFiles)
} else {
allFiles <- moreFiles
}
}
return(allFiles)
}
## Try with your directory?
fileFun(m)
答案 2 :(得分:0)
files = list.files(m ,recursive = T)
music.df <- data.frame( artist = sapply(strsplit(files, '/'), '[[', 7), song = paste( sapply(strsplit(files, '/'), '[[', 8), sapply(strsplit(files, '/'), '[[', 9) , sep = '/' ) )
out <- split( music.df[,2] , f = music.df$artist )
我将艺术家和专辑/标题放入数据框,然后使用split
将数据框拆分为艺术家列表
或者您可以创建strsplit
输出的数据框,然后在数据框上使用split
。
(ncol将根据文件夹的深度而变化)
files = list.files(m ,recursive = T)
music.df <- data.frame(matrix(unlist(strsplit(files, '/')), ncol = 9, byrow = T) )
out <- split( music.df[,9] , f = music.df[7:8])