在 Common Lisp 中正确解压 Excel 文件

问题描述 投票:0回答:1

这是一个后续问题 在 MacBook 中使用 Common Lisp 创建名称中带有方括号的文件会产生问题。我该怎么办?

这是我自己回答的,因为 ChatGPT 给了我答案。

但是在尝试解压缩 Excel 文件(其中包含名称中带有方括号的“[Content_Type].xml”文件)的过程中,这会产生问题, 我意识到

zip
库 - 及其
unzip
函数在解压缩这个方括号名称时也存在问题。

unzip函数的源代码在这里https://github.com/mcna/zip/blob/master/zip.lisp 它是这样的:

(defun unzip (pathname target-directory &key (if-exists :error) verbose)
  ;; <Xof> "When reading[1] the value of any pathname component, conforming
  ;;       programs should be prepared for the value to be :unspecific."
  (when (set-difference (list (pathname-name target-directory)
                              (pathname-type target-directory))
                        '(nil :unspecific))
    (error "pathname not a directory, lacks trailing slash?"))
  (with-zipfile (zip pathname)
    (do-zipfile-entries (name entry zip)
      (let ((filename (merge-pathnames name target-directory)))
        (ensure-directories-exist filename)
        (unless (char= (elt name (1- (length name))) #\/)
          (ecase verbose
            ((nil))
            ((t) (write-string name) (terpri))
            (:dots (write-char #\.)))
          (force-output)
          (with-open-file
              (s filename :direction :output :if-exists if-exists
               :element-type '(unsigned-byte 8))
            (zipfile-entry-contents entry s)))))))

我们来看一个 Excel 文件。 并使用此功能解压缩它。 我手动创建了一个 Excel 文件。然后指定它的路径:

(defparameter *xlsx* "/Users/<user-name>/Downloads/test.xlsx")
(ql:quickload :zip)
(zip:unzip *xlsx* "/Users/<user-name>/Downloads/test_zip/")

它与我在上一篇文章中遇到的问题完全相同。

bad place for a wild pathname
   [Condition of type SB-INT:SIMPLE-FILE-ERROR]

Restarts:
 0: [RETRY] Retry SLY mREPL evaluation request.
 1: [*ABORT] Return to SLY's top level.
 2: [ABORT] abort thread (#<THREAD tid=5123 "sly-channel-1-mrepl-remote-1" RUNNING {70051404E3}>)

Backtrace:
 0: (SB-KERNEL::%FILE-ERROR #P"/Users/<user-name>/Downloads/test_zip/[Content_Types].xml" "bad place for a wild pathname")
      Locals:
        ARGUMENTS = NIL
        DATUM = "bad place for a wild pathname"
        PATHNAME = #P"/Users/<user-name>/Downloads/test_zip/[Content_Types].xml"
 1: (ENSURE-DIRECTORIES-EXIST #P"/Users/<user-name>/Downloads/test_zip/[Content_Types].xml" :VERBOSE NIL :MODE 511)
      Locals:
        #:.DEFAULTING-TEMP. = NIL
        #:.DEFAULTING-TEMP.#1 = 511
        SB-IMPL::CREATED-P = NIL
        PATHNAME = #P"/Users/<user-name>/Downloads/test_zip/[Content_Types].xml"
        SB-IMPL::PATHSPEC = #P"/Users/<user-name>/Downloads/test_zip/[Content_Types].xml"
 2: (ZIP:UNZIP "/Users/josephus/Downloads/test.xlsx" "/Users/<user-name>/Downloads/test_zip/" :IF-EXISTS :ERROR :VERBOSE NIL :FORCE-UTF-8 NIL)
      Locals:
        #:.DEFAULTING-TEMP. = NIL
        FILENAME = #P"/Users/<user-name>/Downloads/test_zip/[Content_Types].xml"
        FORCE-UTF-8 = NIL
        IF-EXISTS = :ERROR
        PATHNAME = "/Users/<user-name>/Downloads/test.xlsx"
        TARGET-DIRECTORY = "/Users/josephus/Downloads/test_zip/"
        ZIP = #S(ZIP:ZIPFILE :STREAM #<SB-SYS:FD-STREAM for "file /Users/<user-name>/Downloads/test.xlsx" {700888DB43}> :ENTRIES #<HASH-TABLE :TEST EQUAL :COUNT 11 {70088A23A3}>)
 3: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ZIP:UNZIP *XLSX* "/Users/<user-name>/Downloads/test_zip/") #<NULL-LEXENV>)
 4: (EVAL (ZIP:UNZIP *XLSX* "/Users/<user-name>/Downloads/test_zip/"))
 5: ((LAMBDA NIL :IN SLYNK-MREPL::MREPL-EVAL-1))

有人知道如何处理吗?

我问了chatGPT,它建议:

 (defun better-unzip (pathname target-directory &key (if-exists :error) verbose)
  "Unzip function that handles square brackets in filenames correctly."
  (zip:with-zipfile (zip pathname)
    (zip:do-zipfile-entries (name entry zip)
      (let ((filename (make-pathname :directory target-directory
                                     :name (pathname-name (parse-namestring name))
                                     :type (pathname-type (parse-namestring name)))))
        (ensure-directories-exist filename)
        (unless (char= (elt name (1- (length name))) #\/)
          (ecase verbose
            ((nil))
            ((t) (write-string name) (terpri))
            (:dots (write-char #\.)))
          (force-output)
          (with-open-file (s filename :direction :output :if-exists if-exists
                            :element-type '(unsigned-byte 8))
            (zip:zipfile-entry-contents entry s)))))))

然后我做了:

(better-unzip *xlsx* "/Users/<your-user-name>/Downloads/test_zip/")

但是我又遇到了:

bad place for a wild pathname
   [Condition of type SB-INT:SIMPLE-FILE-ERROR]

Restarts:
 0: [RETRY] Retry SLY mREPL evaluation request.
 1: [*ABORT] Return to SLY's top level.
 2: [ABORT] abort thread (#<THREAD tid=5123 "sly-channel-1-mrepl-remote-1" RUNNING {70051404E3}>)

Backtrace:
 0: (SB-KERNEL::%FILE-ERROR #P"//Users/<user-name>/Downloads/test_zip//[Content_Types].xml" "bad place for a wild pathname")
 1: (ENSURE-DIRECTORIES-EXIST #P"//Users/<user-name>/Downloads/test_zip//[Content_Types].xml" :VERBOSE NIL :MODE 511)
 2: (BETTER-UNZIP "/Users/josephus/Downloads/test.xlsx" "/Users/<user-name>/Downloads/test_zip/" :IF-EXISTS :ERROR :VERBOSE NIL)
 3: (SB-INT:SIMPLE-EVAL-IN-LEXENV (BETTER-UNZIP *XLSX* "/Users/<user-name>/Downloads/test_zip/") #<NULL-LEXENV>)
 4: (EVAL (BETTER-UNZIP *XLSX* "/Users/<user-name>/Downloads/test_zip/"))
 5: ((LAMBDA NIL :IN SLYNK-MREPL::MREPL-EVAL-1))
macos zip lisp common-lisp unzip
1个回答
0
投票

我会打电话

(ensure-directories-exist "/Users/foo/dir/")

而不是

(ensure-directories-exist "/Users/foo/dir/[a].b")
© www.soinside.com 2019 - 2024. All rights reserved.