我正在尝试将一些用于读取/写入 xlsx 文件的 Racket 包转换为 Common Lisp,但遇到了问题。 Excel 文件只不过是一束具有严格规范的压缩 xml 文件。 其中有一个
[Content_type].xml
或 [Content_Type].xml
文件。
尝试在 MacBook 中生成并写入名称中带有方括号的文件会生成错误:
(defparameter *zip-xlsx-temp-directory* "test-directory/")
(defparameter *content-type-file* (merge-pathnames "[Content_Types].xml" *zip-xlsx-temp-directory*))
(with-open-file (stream (ensure-directories-exist *content-type-file-1*)
:direction :output
:if-does-not-exist :create
:if-exists :supersede)
(format stream ""))
bad place for a wild pathname
[Condition of type SB-INT:SIMPLE-FILE-ERROR]
Restarts:
0: [RETRY] Retry SLY interactive evaluation request.
1: [*ABORT] Return to SLY's top level.
2: [ABORT] abort thread (#<THREAD tid=11295 "slynk-worker" RUNNING {70073BBFC3}>)
Backtrace:
0: (SB-KERNEL::%FILE-ERROR #P"test-directory/[Content_Types].xml" "bad place for a wild pathname")
Locals:
ARGUMENTS = NIL
DATUM = "bad place for a wild pathname"
PATHNAME = #P"test-directory/[Content_Types].xml"
1: (ENSURE-DIRECTORIES-EXIST #P"test-directory/[Content_Types].xml" :VERBOSE T :MODE 511)
Locals:
#:.DEFAULTING-TEMP. = T
#:.DEFAULTING-TEMP.#1 = 511
SB-IMPL::CREATED-P = NIL
PATHNAME = #P"/Users/josephus/.roswell/local-projects/cl-simple-xlsx/tests/test-directory/[Content_Types].xml"
SB-IMPL::PATHSPEC = #P"test-directory/[Content_Types].xml"
2: ((LAMBDA ()))
3: (SB-INT:SIMPLE-EVAL-IN-LEXENV (WITH-OPEN-FILE (STREAM (ENSURE-DIRECTORIES-EXIST *CONTENT-TYPE-FILE-1* :VERBOSE T) :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE ...) (FORMAT STREAM "")) #<NULL-LEXENV>)
4: (EVAL (WITH-OPEN-FILE (STREAM (ENSURE-DIRECTORIES-EXIST *CONTENT-TYPE-FILE-1* :VERBOSE T) :DIRECTION :OUTPUT :IF-DOES-NOT-EXIST :CREATE ...) (FORMAT STREAM "")))
5: ((LAMBDA NIL :IN SLYNK:INTERACTIVE-EVAL))
6: (SLYNK::CALL-WITH-RETRY-RESTART "Retry SLY interactive evaluation request." #<FUNCTION (LAMBDA NIL :IN SLYNK:INTERACTIVE-EVAL) {70073E8F3B}>)
7: (SLYNK::CALL-WITH-BUFFER-SYNTAX NIL NIL #<FUNCTION (LAMBDA NIL :IN SLYNK:INTERACTIVE-EVAL) {70073E8F1B}>)
8: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SLYNK:INTERACTIVE-EVAL "(with-open-file (stream (ensure-directories-exist *content-type-file-1* :verbose t) ..)
9: (EVAL (SLYNK:INTERACTIVE-EVAL "(with-open-file (stream (ensure-directories-exist *content-type-file-1* :verbose t) ..)
10: (SLYNK:EVAL-FOR-EMACS (SLYNK:INTERACTIVE-EVAL "(with-open-file (stream (ensure-directories-exist *content-type-file-1* :verbose t) ..)
11: ((LAMBDA NIL :IN SLYNK::SPAWN-WORKER-THREAD))
12: (SLYNK-SBCL::CALL-WITH-BREAK-HOOK #<FUNCTION SLYNK:SLYNK-DEBUGGER-HOOK> #<FUNCTION (LAMBDA NIL :IN SLYNK::SPAWN-WORKER-THREAD) {70073E8C6B}>)
13: ((FLET SLYNK-BACKEND:CALL-WITH-DEBUGGER-HOOK :IN "/Users/josephus/.roswell/lisp/sly/git/slynk/backend/sbcl.lisp") #<FUNCTION SLYNK:SLYNK-DEBUGGER-HOOK> #<FUNCTION (LAMBDA NIL :IN SLYNK::SPAWN-WORKER-T..
14: ((LAMBDA NIL :IN SLYNK::CALL-WITH-LISTENER))
15: (SLYNK::CALL-WITH-BINDINGS ((*PACKAGE* . #<PACKAGE "CL-SIMPLE-XLSX/TESTS/MAIN">) (*DEFAULT-PATHNAME-DEFAULTS* . #P"/Users/josephus/.roswell/local-projects/cl-simple-xlsx/tests/") (* . #1="+01:00") (**..
16: ((LAMBDA NIL :IN SLYNK::SPAWN-WORKER-THREAD))
17: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
18: ((FLET "WITHOUT-INTERRUPTS-BODY-" :IN SB-THREAD::RUN))
19: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
20: ((FLET "WITHOUT-INTERRUPTS-BODY-" :IN SB-THREAD::RUN))
21: (SB-THREAD::RUN)
这似乎是 Lisp 固有的问题。
使用我的 Python(在 ipython zshell 中)并执行以下操作:
with open("[Content_Types].xml", "w") as f:
f.write("<H1>Hi</H1>")
工作没有错误。
我尝试了 (truename path) 或转义名称“[Content_Types].xml”或“\[Content_Types\].xml”中的括号 - 如果转义第一个似乎是正确的。但这没有帮助。仍然出现错误的通配符错误。
写完之后,我尝试在Linux(Ubuntu)中重现它,然后查阅了ChatGPT。它最初的答案(使用
truename
并转义括号是错误的)。
所以我认为其他人在直接询问 ChatGPT 时可能也会遇到这个问题。
解决方案是:
如果您必须在 macOS 上的 Common Lisp 中使用带括号的文件名(例如,[Content_Types].xml),请务必确保在处理文件操作时正确处理这些括号。具体方法如下:
1. Use make-pathname to create pathnames:
This can avoid issues with special characters.
(defparameter *content-type-file*
(make-pathname :directory content-dir :name "[Content_Types]" :type "xml"))
2. Pass the pathname directly to with-open-file:
;; so I did first:
(defparameter *content-dir* "/Users/<your-user-name>/Downloads/test-zip/")
(ensure-directories-exist *content-dir*)
(defparameter *content-type-file*
(make-pathname :directory *content-dir* :name "[Content_Types]" :type "xml"))
;; and then - step 2:
(with-open-file (stream *content-type-file*
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
(format stream "<H1/>"))
;; => NIL
然后它正确创建了名称中带有方括号的文件。