贡献者: 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"]