当您使用%sh 时,您正在使用其本地文件系统在驱动程序节点上执行shell 命令。但是,/FileStore/ 不在本地文件系统中,这就是您遇到问题的原因。你可以试试看:
%sh ls /FileStore
# ls: cannot access '/FileStore': No such file or directory
对比
dbutils.fs.ls("/FileStore")
// resX: Seq[com.databricks.backend.daemon.dbutils.FileInfo] = WrappedArray(...)
您必须使用可用于 Databricks 文件系统的解压缩实用程序,或者必须将 zip 从文件存储复制到驱动程序磁盘,解压缩然后复制回/FileStore。
您可以使用file:/... 寻址本地文件系统,例如,
dbutils.fs.cp("/FileStore/file.zip", "file:/tmp/file.zip")
希望这会有所帮助。
旁注 1:Databricks 文件系统管理不是超级直观,尤其是在文件存储方面。例如,理论上,Databricks 文件系统 (DBFS) 在本地挂载为 /dbfs/。但是,/dbfs/FileStore 不处理文件存储,而dbfs:/FileStore 处理。你并不孤单。 :)
旁注 2:如果您需要对许多文件执行此操作,您可以通过创建带有文件路径的 Dataset[String] 而不是 ds.map { name => ... }.collect() 来将工作分配给集群工作人员。 collect 操作将强制执行。在 map 函数的主体中,您必须使用 shell API 而不是 %sh。
旁注 3:不久前,我使用以下 Scala 实用程序在 Databricks 上解压缩。无法验证它是否仍然有效,但它可以给你一些想法。
def unzipFile(zipPath: String, outPath: String): Unit = {
val fis = new FileInputStream(zipPath)
val zis = new ZipInputStream(fis)
val filePattern = """(.*/)?(.*)""".r
println("Unzipping...")
Stream.continually(zis.getNextEntry).takeWhile(_ != null).foreach { file =>
// @todo need a consistent path handling abstraction
// to address DBFS mounting idiosyncracies
val dirToCreate = outPath.replaceAll("/dbfs", "") + filePattern.findAllMatchIn(file.getName).next().group(1)
dbutils.fs.mkdirs(dirToCreate)
val filename = outPath + file.getName
if (!filename.endsWith("/")) {
println(s"FILE: ${file.getName} to $filename")
val fout = new FileOutputStream(filename)
val buffer = new Array[Byte](1024)
Stream.continually(zis.read(buffer)).takeWhile(_ != -1).foreach(fout.write(buffer, 0, _))
}
}
}