簡體   English   中英

如何從 python 讀取、更改和寫入 macOS 文件別名

[英]how to read, change, and write macOS file alias from python

有沒有辦法讀取 macOS 文件別名、修改其內容(尤其是目標文件路徑)並將修改后的別名寫回?

例如,如果我有以下目錄結構:

./one/file.txt
./two/file.txt
./file_alias

其中file_alias解析為./one/file.txt 我希望能夠以編程方式在 Python 中讀取./file_alias ,確定其路徑,將“一”更改為“二”,然后寫出修改后的別名,覆蓋./file_alias 完成后, file_alias將解析為./two/file.txt

搜索我找到了一個相關問題的答案,表明它無法完成(@Milliway 對 [1] 的回答),一個沒有實質性文檔的 Carbon 模塊和一個聲明其功能已被刪除 [2],一個部分棄用的 macostools 模塊,它依賴於 Carbon [3],一個等效的未回答的問題(除了使用 PyObjC 的初步建議)[4],以及最近更新的 mac_alias 包 [5],但還沒有找到完成任務的方法基於其中任何一個。

mac_alias 包起初看起來很有趣,但我發現無法從現有別名文件中導入構建內存中Alias對象所需的字節(使用別名文件的二進制讀取中的字節會產生錯誤),即使我可以構造內存中的Alias記錄並對其進行修改,但無法將其寫出到磁盤。

我想要的機器運行的是 10.12.x (Sierra),我使用的是內置的 python 2.7.10。 我發現我實際上可以導入 Carbon 和 macostools,並且懷疑 Carbon.File 可能會提供我需要的東西,但我找不到任何文檔。 我可以升級到 High Sierra 和/或安裝和使用 Python 3.x,但這些在現階段似乎沒有幫助或相關。

我意識到別名還包含一個 inode,在這樣的更改后它將過時,但幸運的是,部分原因是我提交的錯誤和我在 Apple 工作時的一些持久性,別名首先解決了路徑,只有如果路徑解析失敗,則回退到 inode,如果路徑解析成功(並且 inode 已更改),則更新 inode。

任何幫助,建議,指針表示贊賞。

[1] 如何使用 os.walk() 在 Python 中處理 OSX 別名?
[2] https://docs.python.org/2/library/carbon.html
[3] https://docs.python.org/2/library/macotools.html
[4] 更改別名目標python
[5] https://pypi.python.org/pypi/mac_alias

使用 PyObjC 解決了這個問題,盡管幾乎沒有 PyObjC 的文檔。 您必須小心地將 NSURL 的 ObjectiveC 接口轉換為 PyObjC 調用,使用本站點上的“PyObjC 簡介”中描述的技術,同時參考此處描述的 NSURL 接口。

@MagerValp 對這個問題的回復中的代碼有助於找出如何獲取別名的目標。 我必須弄清楚如何使用修改后的目標創建新別名。

下面是一個測試程序,其中包含並練習了所有需要的功能。 它的設置和使用記錄在代碼中的注釋中。

我是一個壞人,沒有做文檔字符串或輸入和返回值的描述,但我讓所有函數都簡短且具有單一功能,希望我已經足夠清楚地命名了所有變量和函數,以至於不需要它們. CamelCaps 和 underscore_separated 變量和函數名有一個公認的奇怪組合。 我通常將 CamelCaps 用於全局常量,並為函數和變量使用 underscore_separated 名稱,但在這種情況下,我想保持 PyObjC 調用中引用的變量和數據類型(使用 camelCaps)不變,因此是奇怪的組合。

請注意,Mac Finder 會緩存一些有關別名的信息。 因此,如果您在運行此程序后立即對file_alias執行獲取信息或解析,即使它確實起作用,它看起來也不起作用。 您必須將one文件夾拖到廢紙簍清空廢紙簍,只有這樣,獲取信息或解析file_alias顯示它現在確實指向./two/file.txt (抱怨,抱怨。)幸運的是,我懷疑這不會影響我對這些技術的使用,也不會影響大多數人的使用。 該程序的重​​點通常是將損壞的別名替換為固定的別名,基於這樣一個事實,即一些單一的、簡單的事情發生了變化,例如本例中的文件夾名稱,或我實際應用程序中的卷名稱。

最后,代碼:

#!/usr/bin/env python

# fix_alias.py
# A test program to exercise functionality for retargeting a macOS file alias (bookmark).
# Author: Larry Yaeger, 20 Feb 2018
#
# Create a file and directory hierarchy like the following:
#
# one
#   file.txt
# two
#   file.txt
# file_alias
#
# where one and two are folders, the file.txt files are any files really, and
# file_alias is a Mac file alias that points to ./one/file.txt.  Then run this program
# in the same folder as one, two, and file_alias.  It will replace file_alias with
# an alias that points to ./two/file.txt.
#
# Note that file_alias is NOT a symbolic link, even though the Mac Finder sometimes
# pretends symbolic links are aliases; they are not.

import os
import string

from Foundation import *


OldFolder = 'one'
NewFolder = 'two'
AliasPath = 'file_alias'


def get_bookmarkData(alias_path):
  alias_url = NSURL.fileURLWithPath_(alias_path)
  bookmarkData, error = NSURL.bookmarkDataWithContentsOfURL_error_(alias_url, None)
  return bookmarkData


def get_target_of_bookmarkData(bookmarkData):
  if bookmarkData is None:
    return None
  options = NSURLBookmarkResolutionWithoutUI | NSURLBookmarkResolutionWithoutMounting
  resolved_url, stale, error = \
    NSURL.URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(
      bookmarkData, options, None, None, None)
  return resolved_url.path()


def create_bookmarkData(new_path):
  new_url = NSURL.fileURLWithPath_(new_path)
  options = NSURLBookmarkCreationSuitableForBookmarkFile
  new_bookmarkData, error = \
    new_url.bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(
      options, None, None, None)
  return new_bookmarkData


def create_alias(bookmarkData, alias_path):
  alias_url = NSURL.fileURLWithPath_(alias_path)
  options = NSURLBookmarkCreationSuitableForBookmarkFile
  success, error = NSURL.writeBookmarkData_toURL_options_error_(bookmarkData, alias_url, options, None)
  return success


def main():
  old_bookmarkData = get_bookmarkData(AliasPath)
  old_path = get_target_of_bookmarkData(old_bookmarkData)
  print old_path
  new_path = string.replace(old_path, OldFolder, NewFolder, 1)
  new_bookmarkData = create_bookmarkData(new_path)
  new_path = get_target_of_bookmarkData(new_bookmarkData)
  print new_path
  os.remove(AliasPath)
  create_alias(new_bookmarkData, AliasPath)


main()

這個話題引起了我的興趣...

但我認為這是不可能的。

在 mac_alias 中查看此錯誤報告: https : //github.com/al45tair/mac_alias/issues/4

它指出該包處理別名記錄而不是別名文件 Alias 文件是第三個版本,尚未進行逆向工程。

它指向別名文件中的此信息:http ://indiestack.com/2017/05/resolving-modern-mac-alias-files/

還有這個關於他們舊 bitbucket 的線程: https ://bitbucket.org/al45tair/mac_alias/issues/3/support-for-version-3-aliases

指向這個死頁(感謝,archive.org) https://web.archive.org/web/20170222235430/http://sysforensics.org/2016/08/mac-alias-data-objects/

以及可以通過這個包讀取一些信息的信息: https : //pypi.python.org/pypi/plistutils/有一堆關於在他們的 github 上讀取別名結構的文檔

這些都沒有你想要的。 對不起。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM