如何从python读取、更改和写入macOS文件别名

2024-10-04 01:25:31 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有办法读取macOS文件别名,修改其内容(尤其是目标文件路径),然后将修改后的别名写回原处?在

例如,如果我有以下目录结构:

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

其中file_alias解析为./one/file.txt。我希望能够在Python中以编程方式读取./file_alias,确定其路径,将'one'更改为'two',并写出修改后的别名,覆盖./file_alias。完成后,file_alias将解析为./two/file.txt。在

通过搜索,我找到了一个相关问题的答案,该问题表明它无法实现(@Milliway对[1]的回答),一个没有实质性文档的碳模块,一个功能已被删除的声明[2],一个部分弃用的依赖碳的macostools模块[3],一个等价物,未回答的问题(除了暂时建议使用PyObjC)[4]和最近更新的mac_alias包[5],但还没有找到一种方法来完成这项任务。在

mac\'alias包一开始看起来很有趣,但我没有找到从现有别名文件导入构造内存中Alias对象所需的字节(使用别名文件的二进制读取中的字节会产生错误),即使我可以构造内存中的Alias记录并对其进行修改,也无法将其写出到磁盘。在

我想要的机器运行的是10.12.x(Sierra),我使用的是内置的python2.7.10。我发现我可以进口碳和麦角醇碳纤维。锉刀可能会提供我需要的,但我找不到任何文档。我可以升级到High Sierra和/或安装并使用Python3.x,但这些在现阶段似乎没有帮助或相关。在

我意识到别名中还包含一个inode,在这样的更改之后它将是过时的,但值得庆幸的是,部分原因是我在Apple时提交的一个bug和一点持久性,别名首先解析路径,只有在路径解析失败时才会返回到inode,如果路径确实解析了(inode已经更改)。在

任何帮助,建议,指点都很感激。在

[1]How to handle OSX Aliases in Python with os.walk()?
[2] https://docs.python.org/2/library/carbon.html
[3] https://docs.python.org/2/library/macostools.html
[4] change an alias target python
[5] https://pypi.python.org/pypi/mac_alias


Tags: 模块文件文档httpsorg路径txtmac
2条回答

使用PyObjC解决了这个问题,尽管几乎没有关于PyObjC的文档。您必须小心地将NSURL调用的ObjectiveC接口转换为PyObjC,使用在this site上找到的“PyObjC简介”中描述的技术,同时引用here中描述的NSURL接口。在

@MagerValp对this question的回复中的代码有助于找出如何获取别名的目标。我不得不想出如何用修改后的目标创建一个新别名。在

下面是一个测试程序,它包含并练习了所需的所有功能。它的设置和使用在代码中用注释记录下来。在

我是个坏人,不做doc字符串或者输入和返回值的描述,但是我保持了所有函数的简短和单一函数,希望我已经足够清楚地命名了所有变量和函数,使它们不再需要。有一个公认的奇怪的组合,CamelCaps和下划线_分开的变量和函数名。我通常对全局常量使用CamelCaps,对函数和变量使用下划线分隔的名称,但在本例中,我希望保持PyObjC调用中引用的变量和数据类型不变,这是一种奇怪的混合。在

警告一下,macfinder会缓存一些关于别名的信息。因此,如果您在运行这个程序之后立即对file_alias执行Get Info或解析,那么它看起来好像不起作用,尽管它确实起了作用。您必须将one文件夹拖到Trash并清空垃圾桶,只有这样,file_alias的Get Info或解析才会显示它现在确实指向./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\u alias中查看这个bug报告:https://github.com/al45tair/mac_alias/issues/4

它注意到这个包处理Alias记录而不是Alias文件。Alias文件是尚未进行反向工程的第三个版本。在

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

在他们的旧比特桶上还有这个线程:https://bitbucket.org/al45tair/mac_alias/issues/3/support-for-version-3-aliases

这就是这张死页(谢谢,存档.org)https://web.archive.org/web/20170222235430/http://sysforensics.org/2016/08/mac-alias-data-objects/

通过这个包可以读取一些信息:https://pypi.python.org/pypi/plistutils/,这个包有一堆关于读取github上别名结构的文档

但这一切你都不想要。对不起的。在

相关问题 更多 >