若您曾尝试使用基于 POSIX 的程序处理 VOS 结构化文件,可能会遇到某些限制或遇到难以理解的行为。本文将尝试解释其中缘由。
VOS支持四种文件类型:顺序文件、相对文件、固定文件和流文件。前三种格式被称为“结构化”文件,因为文件系统会记录记录边界。可用的I/O操作会读取和写入完整的记录。最后一种格式被称为“非结构化”文件,因为记录边界是隐式的;换行符作为记录分隔符。可用的I/O操作会读取和写入字节序列。
符合 POSIX 标准的环境(如 Unix® 或 Linux© 系统)仅有一种原生文件类型,称为“常规文件”。VOS 流文件组织与 POSIX 常规文件等效。
VOS POSIX运行时环境将所有四种类型的文件都归类为POSIX普通文件。因此至少在理论上,任何POSIX程序都能读取或写入这四种文件类型。然而实际情况并非如此简单。
由于POSIX API将所有I/O操作定义为字节序列,而VOS将I/O操作(针对结构化文件)定义为记录序列,VOS POSIX运行时通过在用户空间缓冲当前记录、对缓冲区执行POSIX I/O操作,然后在适当位置将缓冲记录写回的方式来弥合这种差异。
如果POSIX程序知道每条记录的大小(例如对于固定长度文件),并且读写精确的字节数,那么缓冲区的存在不会影响操作,两种I/O操作的映射关系也易于理解且高效。
但若POSIX程序仅读写字节流而不考虑底层记录大小,则其语义向VOS语义的映射虽定义明确,却普遍缺乏实用价值且效率低下。某些操作——例如跳转至特定字节位置,或重写跨越记录边界的字节序列——在最佳情况下效率低下,最坏情况下则完全无法实现。
然后还有换行符的处理问题。
POSIX常规文件和VOS流文件均使用换行符来区分记录边界。然而,结构化文件中的VOS记录通常不包含任何换行符。例如,当VOS编辑器(如edit、emacs或line_edit)创建新的顺序文件时,每条记录包含一行文本,但记录末尾并不以换行符结束。 按惯例,所有程序均默认包含文本的顺序文件会在每条记录末尾隐含换行符。相对文件和固定文件亦遵循此规则。但需注意关键点:任何文件(VOS、Unix、结构化或非结构化)的属性均不记录文件是否包含文本或二进制数据。该区分权完全交由访问文件的程序自行判断。
这种情况给VOS POSIX运行时环境带来了一定困扰。它需要判断VOS结构化文件中包含的是文本还是数据,从而决定是否在每条记录末尾追加换行符。若文件包含文本,则应追加换行符;若包含数据,则不应追加换行符。
答案是:VOS POSIX运行时依赖调用方提供此信息。默认情况下,POSIX运行时将结构化文件视为文本文件,并在末尾添加换行符;调用方可通过提供O_TEXT打开模式显式要求此行为。 若调用方希望将VOS结构化文件视为数据文件,则必须使用O_BINARY打开模式。这两种模式互斥:指定其中一种时,不得同时指定另一种。对于流文件,这些模式无需指定,因此在此情况下将被忽略。
对于正在阅读本文的语言规范专家,我需要特别说明:O_TEXT 和 O_BINARY 均为 POSIX 标准的扩展属性,并非 POSIX 标准本身定义的特性。这类属性通常仅存在于能够区分文本文件与二进制文件的操作系统(如 VOS 系统),或采用特殊换行符规范的系统(如 Windows 系统使用的 CR-LF 组合)。
根据政策,Stratus 基于POSIX的软件Stratus OpenVOSStratus ,我们会修改其代码以排除对FIXED和RELATIVE文件的使用,并将SEQUENTIAL文件限制为只读访问。 我们同时假定所有顺序文件均包含文本内容。实践表明,这些规则使得将STREAM或SEQUENTIAL文件作为POSIX程序的输入成为可行方案,同时避免了在顺序输出文件上执行字节级操作时固有的低效问题。
总而言之,最佳做法是仅使用STREAM文件(用于输入或输出)和SEQUENTIAL文件(仅用于文本输入)来配合基于POSIX的程序。 若结构化文件中包含二进制数据,请编写小型程序将其复制到流文件中,再使用该流文件版本进行POSIX程序处理。若固定长度或相对长度文件中的文本数据需通过POSIX程序处理,请先将文件复制到流文件中。
