我试图重命名给定目录中的所有文件和子目录.我创建旧名称和新名称的向量,并在两个向量上映射重命名函数.文件路径的向量是创建好的,但映射
(map #(re-name (as-file %1) (as-file %2)) flist new-flist)))似乎根本没有调用重命名函数(我已经在其中放置了一个打印调用来测试).经过大量的调整和搜索后,我仍然对我所缺少的东西感到困惑.
此外,我想知道如何通过逐步调试代码来避免诉诸论坛.
码:
;;;; Use: Replaces whitespace in names of all directories and files in the given directory with the given separator.
(ns file-renamer.core
(:gen-class)
(:require [clojure.string :as str]))
(use '[clojure.java.io])
(use '[clojure.pprint])
; Constants for testing -> params live
(def direc "/home/john/test/")
(def separator "-")
; ====================================
(defn traverse-dir
"Return a seq of pathnames of directories and files in the given directoryt"
[dir-path]
(map #(.getAbsolutePath %) (file-seq (file dir-path))))
(defn replace-spaces
"Return a copy of string s1 with all sequences of spaces replaced with string s2"
[s1 s2]
(str/replace s1 #"\s+" s2))
(defn re-name
"Rename a file"
[old-file new-file]
(pprint (str "Renaming: " old-file " ==>> " new-file)) ; put here for debugging
(.renameTo old-file new-file))
(defn -main
"Map a fn to rename a file over all files and dirs in the given directory"
[& args]
(let [flist (vec (traverse-dir direc))
new-flist (vec (map #(replace-spaces % separator) flist))]
(pprint flist)
(pprint new-flist)
(map #(re-name (as-file %1) (as-file %2)) flist new-flist)))
Run Code Online (Sandbox Code Playgroud)
输出:
17 Mar 20:53 /file-renamer ? lein run
["/home/john/test"
"/home/john/test/test 108"
"/home/john/test/test 108/ baaaa rrrr"
"/home/john/test/test 108/ baaaa rrrr/Open Document Text .... odt"
"/home/john/test/test 108/ baaaa rrrr/ba z z er ."
"/home/john/test/test 108/ baaaa rrrr/ba z z er ./freed.frm"
"/home/john/test/test 108/ baaaa rrrr/ba z z er ./New Folder"
"/home/john/test/test 108/ baaaa rrrr/ba z z er ./New Folder/Plain Text.txt"
"/home/john/test/test 108/ baaaa rrrr/ba z z er ./fr ed.txt"
"/home/john/test/test 108/s p a c e s------S P A C E S "
"/home/john/test/fox"
"/home/john/test/foo"
"/home/john/test/fog"]
["/home/john/test"
"/home/john/test/test-108"
"/home/john/test/test-108/-baaaa-rrrr"
"/home/john/test/test-108/-baaaa-rrrr/Open-Document-Text-....-odt"
"/home/john/test/test-108/-baaaa-rrrr/ba-z-z-er-."
"/home/john/test/test-108/-baaaa-rrrr/ba-z-z-er-./freed.frm"
"/home/john/test/test-108/-baaaa-rrrr/ba-z-z-er-./New-Folder"
"/home/john/test/test-108/-baaaa-rrrr/ba-z-z-er-./New-Folder/Plain-Text.txt"
"/home/john/test/test-108/-baaaa-rrrr/ba-z-z-er-./fr-ed.txt"
"/home/john/test/test-108/s-p-a-c-e-s------S-P-A-C-E-S-"
"/home/john/test/fox"
"/home/john/test/foo"
"/home/john/test/fog"]
17 Mar 20:53 /file-renamer ?
Run Code Online (Sandbox Code Playgroud)
小智 6
这里有几个问题.它们不是你的错,但更多的是REPL正在对你起作用,而你还没有完全理解(可能)Clojure和懒惰操作/序列的核心概念.
map函数返回一个懒惰的序列,需要在某个时间点实现,而你没有这样做.最重要的是,重命名功能不是副作用自由功能(纯函数).REPL也在玩弄你:如果你在REPL上调用(-main),它会自动实现这些序列,并且会给Clojure的新手带来很多混乱.
最直接的解决方案是使用doall函数.
(doall (map #(re-name (as-file %1) (as-file %2)) flist new-flist))
Run Code Online (Sandbox Code Playgroud)
但这是快速而肮脏的方式,我将在这里引用Stuart Sierra:
您可能会得到一些建议,您可以"强制"使用doall或dorun来评估惰性序列.还有一些片段浮动,声称"unchunk"序列.
在我看来,doall,dorun甚至"unchunk"的存在几乎总是一个标志,一开始就不应该是一个懒惰的序列.
在这种情况下,更好的解决方案是使用doseq函数并编写如下内容:
(defn -main
"Map a fn to rename a file over all files and dirs in the given directory"
[& args]
(doseq [file-string (traverse-dir direc)]
(let [input-file (as-file file-string)
output-file (as-file (replace-spaces file-string separator))]
(re-name input-file output-file))))
Run Code Online (Sandbox Code Playgroud)
这也可以写得更短.
斯图尔特·塞拉的博客文章是一篇很有帮助的好读物: Clojure Don'ts:Lazy Effects.
| 归档时间: |
|
| 查看次数: |
134 次 |
| 最近记录: |