贡献者: graviton; addis
Mathematica 中包含了常用的标准文件操作, 同时也可以将算法和高级编程应用于文件和系统管理任务。此介绍主要参考官方页面:
一个重要的原则是:不要直接使用 裸字符串
硬编码 文件名/文件路径
,
这样生成的路径依赖于操作平台的规范,相反:
$UserBaseDirectory/Applications
目录下。
如需获得操作系统细节,可使用:
$OperatingSystem
: 给出正在运行的操作系统的名称。
$PathnameSeparator
: 存储路径分隔符的字符串,可在构建路径时使用。
例如 $UserBaseDirectory <> "\abcd\"
。
Windows 中的默认值是 \\
,其他系统是 /
。
在 Windows 中,FileNameSplit
这类函数默认同时允许 \
和 /
。
.m
:Wolfram 语言源文件
.nb
:Wolfram 系统笔记本文件
.ma
:Wolfram 系统从第 $3$ 版以前的笔记本文件
.mx
:输出所有 Wolfram 语言表达式
.exe
:WSTP 可执行程序
.tm
:WSTP 模版文件
.ml
:WSTP 流文件
Get
,Needs
,Import
,Install
等函数读取本地文件时,默认使用的搜索路径为 $Path
。
全局变量 $Path
被定义为字符串的列表,其中每个字符串代表一个目录。
每次你要求打开文件时,Wolfram 就依次将这些目录暂时设置为当前工作目录,然后从该目录中尝试寻找你要求的文件。
也就是说,如果两个目录中含有同名的文件,排在前面的目录优先,不过你可以通过提供更详细的上层路径来避免歧义。
在 $Path
的典型设置中,当前目录和你的主目录(分别用 。
和 ~
表示)被列在最前。
$InitialDirectory
:Wolfram 系统启动时的初始目录。
$HomeDirectory
: 你的主目录,如果有定义的话
$BaseDirectory
: Wolfram 系统要加载的全系统文件的基本目录。
$UserBaseDirectory
: 用于 Wolfram 系统加载的, 用户自定义文件的基本目录
$InstallationDirectory
: 你的 Wolfram 系统安装的最高级别目录
Wolfram 系统所使用的绝大多数文件都与操作系统无关。
然而,mx
和 .exe
文件与系统有关。
对于这些文件,按照惯例,捆绑上不同计算机系统版本的名称,
形式如 name/$SystemID/name
。
NotebookFileName[]
:给出当前笔记本的完整路径。
NotebookDirectory[]
:笔记本父目录
NotebookOpen["name"]
: 打开已经存在的笔记本 "name"
,返回笔记本对象。"name"
可以是绝对路径。
NotebookOpen["name", options]
:使用指定的选项打开笔记本。
NotebookOpen
则搜索由前端全局选项 NotebookPath
指定的目录。
Visible->False
,NotebookOpen
打开的笔记本将带有此选项,它永远不会显示在屏幕上。
NotebookSave[notebook]
:保存特定笔记本的当前版本。notebook
必须是一个 NotebookObject
.
NotebookSave[notebook, "file"]
,如果 "file"
存在,则不加警告地覆盖它。
NotebookClose[notebook]
:关闭指定的笔记本对象。
NotebookClose[]
:关闭当前在运行的笔记本。
SetDirectory["dir"]
:将当前工作目录设置为 dir
。
SetDirectory[]
等同于 SetDirectory[$HomeDirectory]
。
ResetDirectory[]
; 将当前工作目录重置为之前的值.
DirectoryStack[]
; 给出当前使用的目录序列/目录栈。其中的目录用绝对路径给出。
每次调用 SetDirectory
会在目录栈中压入元素;每次调用 ResetDirectory
会弹出元素。
DirectoryQ
;测试名称是否对应于真实的目录。
DirectoryName["name",n]
:给出路径的父目录,n
代表上升 n
次。
默认情形给出父目录,可以省略 n
。可作用于文件和目录,但不检查目录是否真实存在于硬盘。
DirectoryName[..., OperatingSystem->"os"]
用来给出某种操作系统风格的路径,
选项有 "Windows"
,"MacOSX"
,和 "Unix"
。
ParentDirectory["dir",n]
:给出路径的父目录,n
代表上升 n
次,
只能用于目录,并且要求目录存在于硬盘上。
FileNames[]
:列出当前目录中的所有文件。
FindFile[name]
:找到指定名称的文件,Get[name]
和相关函数使用此函数寻找文件.
FileNameTake["name"]
:从 "name"
的完整路径中提取出最后的文件名。
FileBaseName["file"]
:给出文件的 basename
,也就是不包括 “拓展名。
FileExtension["file"]
:给出文件的 “拓展名。
FileNameDepth["name"]
:给出文件路径的 “深度,文件不必真实存在。
ExpandFileName["name"]
:将 "name"
展开为当前系统规范下的绝对路径,
"name"
的解析相对于你当前的目录。它展开通常的目录指定,如 .
和 ..
;
它只是对文件名进行解析,并不实际搜索指定的文件。
AbsoluteFileName["name"]
:给出 "name"
文件的绝对路径。
与 ExpandFileName
的区别是,它会进入文件系统,检查文件是否真实存在,
其他和 ExpandFileName
类似。
FileNameJoin
:从 “路径” 的列表,组合出完整的文件名
FileNameSplit
:将文件的完整路径分割成列表,相当于逆运算。
FileNameDrop["name",n]
:去掉文件 "name"
路径的前 n
个片段。
如果传入 -n
,那么去掉从末尾开始的 n
个片段。
FileExistsQ["name"]
:检查文件,目录等是否存在。
ContextToFileName["context"]
:给出 Mathematica 上下文规范(Context
)对应的文件名。
假设你有一些 MMA 脚本组成的工程,它们的根目录为 root
。
在脚本中我们经常需要找出工程的根目录,以便于将脚本移动其他路径、甚至其他操作系统时,
能够不影响代码的正常运行。
一个简单的实现是:首先我们建立具有特殊文件名的 锚点
:
例如在 root
中新建 init.wl
文件(或者别的名字,但后面要相应更改)。并写入以下代码:
(*定义程序包的根目录*)
$srcRoot=AbsoluteFileName[DirectoryName[
If[$Notebooks,NotebookFileName[],$InputFileName],1]]
如此,$srcRoot
变量将保存项目的根目录位置。
在其他项目文件(.nb
, .m
, .wl
……)中,添加以下代码:
(*本文件的名称*)
$fileName=If[$Notebooks,NotebookFileName[],$InputFileName];
(*如果在前端执行,就刷新笔记本的标题*)
Once@If[$Notebooks,NotebookWrite[Cells[][[1]],
Cell[Last@FileNameSplit[$fileName],"Title"]]];
(*查找 init.wl, 导入根目录和函数定义*)
Once@Catch@Module[{recurFind,start=1,depMax},
depMax=FileNameDepth[$fileName];(*路径的最大层次*)
(*-------定义递归函数-------*)
recurFind[dep_Integer]:=If[dep<=depMax,
SetDirectory[DirectoryName[$fileName,dep]];
(*如果在当前层能找到 init.wl,就运行它,并把根目录添加到搜索路径*)
If[FileExistsQ["init.wl"],
Get["init.wl"];PrependTo[$Path,$srcRoot];
Throw["The base directory is : "<>$srcRoot];,
(*如果这一层找不到,就上升一层*)
recurFind[dep+1]];
ResetDirectory[];(*重设为之前的目录*),
Throw["I cann't find any init.wl in this project"]];
recurFind[start];
]
(* 记录 master Kernel 的运行模式, 可在并行计算中使用 *)
$inNBook=$Notebooks;echo[DateString[]," <<",$fileName];
运行之后,此脚本文件路径保存在 $fileName
中,工程根目录保存在 $srcRoot
中。
上面已经将根目录添加到 $Path
变量中,因此可以只用文件名调用同目录下的其他脚本:
Get["其他脚本名称.wl"]