当前位置: 首页 > 后端技术 > Node.js

Node.js指南(使用不同文件系统)

时间:2023-04-03 20:51:54 Node.js

使用不同文件系统系统。文件系统行为在使用文件系统之前,您需要知道它的行为方式,不同的文件系统行为不同,并且比其他文件系统具有或多或少的特性:区分大小写、不区分大小写、保留大小写、Unicode格式保留、时间戳解析、扩展属性、inode、Unix权限、备用数据流等。警惕从process.platform推断文件系统行为,例如,不要假设因为您的程序在Darwin上运行,所以您正在处理不区分大小写的文件系统(HFS+),因为用户可能正在使用大小写-敏感文件系统(HFSX)。同样,不要假设因为您的程序在Linux上运行,所以您正在处理支持Unix权限和inode的文件系统,因为您可能在特定的外部驱动器、USB或网络驱动器上。操作系统可能不会轻易推断出文件系统的行为,但一切都不会丢失,您可以探测文件系统以查看它的实际行为,而不是保留每个已知文件系统和行为的(总是不完整的)列表,某些容易存在或不存在可检测的特征通常足以推断其他更难检测的特征的行为。请记住,某些用户可能在工作树的不同路径上安装了不同的文件系统。避免最小公分母方法您可能希望您的程序通过将所有文件名规范化为大写、将所有文件名规范化为NFCUnicode格式以及将所有文件时间戳规范化为1秒分辨率(这是最小公分母)来表现得像最小公分母文件系统方法。不要这样做,您只能安全地与在各个方面都具有完全相同的最低公分母特征的文件系统进行交互,您将无法以用户期望的方式使用更高级的文件系统,并且您会遇到文件名或时间戳冲突,并且您肯定会通过复杂的相关事件链丢失和损坏用户数据,并且您将创建即使不是不可能修复也很难修复的错误。当您以后需要支持只有2秒或24小时时间戳分辨率的文件系统时会发生什么?当Unicode标准发展到包括略有不同的规范化算法时会发生什么(就像过去发生的那样)?最低公分母方法倾向于尝试仅使用“可移植”系统调用来创建可移植程序,这可能会导致程序出现错误,实际上是不可移植的。采用超集方法通过采用超集方法来充分利用您支持的每个平台,例如,便携式备份程序应该在Windows系统之间正确同步btimes(文件或文件夹的创建时间)并且不应破坏或更改btimes,即使Linux系统不支持btimes。同一个可移植备份程序应该在Linux系统之间正确同步Unix权限,并且不应破坏或更改Unix权限,即使Unix权限在Windows系统上不受支持。通过使程序像对待更高级别的文件系统一样对待不同的文件系统,支持所有可能特性的超集:区分大小写、保留大小写、Unicode形式敏感、Unicode形式保留、Unix权限、高分辨率纳秒时间戳、扩展属性等。一旦您在程序中保留了大小写,如果您需要与不区分大小写的文件系统进行交互,则始终可以实现不区分大小写。但是,如果您在程序中删除大小写保留,则无法安全地与大小写保留文件系统进行交互,Unicode格式保留和时间戳解析保留也是如此。如果文件系统为您提供大小写混合的文件名,则将文件名保留在给定的大小写中,如果文件系统为您提供混合Unicode格式或NFC或NFD(或NFKC或NFKD)的文件名,则将文件名保留在确切的顺序中给定的字节数,或者如果文件系统为您提供毫秒时间戳,则以毫秒为单位保留时间戳。当您使用较小的文件系统时,您总是可以适当地缩减采样,使用您需要的比较功能来比较程序运行的文件系统的行为。如果您知道文件系统不支持Unix权限,那么您不应该期望读取您编写的相同Unix权限。如果您知道文件系统不保留大小写,那么您应该准备好在程序创建abc时在目录列表中看到ABC。但是,如果您知道文件系统确实保留大小写,则在检测文件重命名或文件系统区分大小写时,您应该将ABC视为不同于abc的文件名。保留大小写你可以创建一个名为test/abc的目录,有时会惊讶地发现fs.readdir('test')返回['ABC']这不是Node中的错误,Node返回它存储文件名的文件系统,并非所有文件系统都支持大小写保留,并且某些文件系统将所有文件名转换为大写(或小写)。UnicodeFormPreservationCasePreservation和UnicodeFormPreservation是类似的概念,要理解为什么要进行UnicodeFormPreservation,请确保您首先了解为什么要保留大小写,如果理解正确,UnicodeFormPreservation就这么简单。Unicode可以使用几个不同的字节序列对同一个字符进行编码,而几个字符串可能看起来相同但字节序列不同。使用UTF-8字符串时,请注意您的期望与Unicode的工作方式一致。正如您不希望所有UTF-8字符都编码为单个字节一样,您也不应期望人眼看起来相同的几个UTF-8字符串具有相同的字节表示形式,您可以使用ASCII而不是UTF-8预期。您可以创建一个名为test/café的目录(NFCUnicode形式,字节序列<636166c3a9>和string.length===5),有时您会惊讶地发现fs.readdir('test')返回['café'](NFDUnicode形式,字节序列<63616665cc81>和string.length===6),这不是Node中的错误。Node在文件系统上存储时返回文件名,并非所有文件系统都支持Unicode格式保存。例如,HFS+会将所有文件名规范化为几乎总是与NFD相同的形式,不要期望HFS+的行为与NTFS或EXT4相同,反之亦然。不要试图通过规范化来永久更改数据,因为这是一种有漏洞的抽象,它掩盖了文件系统之间的Unicode差异,这会在不解决任何问题的情况下产生问题,相反,保持Unicode相似并仅将规范化用作比较功能。UnicodeFormInsensitivityUnicodeFormInsensitivity和UnicodeFormPreservation是两种经常被误解的不同文件系统行为。正如文件名在存储和传输时被永久规范化为大写一样,不区分大小写有时会被错误地实现,因此文件名的存储和传输是通过将文件名永久规范化为某种Unicode格式(HFS+中的NFD),有时会错误地实现Unicode格式不敏感。通过使用Unicode规范化进行比较,可以在不牺牲Unicode形式保存的情况下更好地实现Unicode形式不敏感。比较不同的Unicode形式Node提供了string.normalize('NFC'/'NFD'),你可以使用它来将UTF-8字符串规范化为NFC或NFD,你永远不应该存储这个函数的输出,只是存储它用作部分一个比较函数来测试两个UTF-8字符串对用户来说是否相同。您可以使用string1.normalize('NFC')===string2.normalize('NFC')或string1.normalize('NFD')===string2.normalize('NFD')作为比较函数,您选择哪个使用Form无所谓。规范化速度很快,但您可能希望使用缓存作为比较函数的输入,以避免多次规范化同一个字符串,如果该字符串不在缓存中则对其进行规范化并缓存它,注意不要存储或保留缓存,仅将其用作缓存。请注意,使用normalize()需要您的Node版本包含ICU(否则normalize()将返回原始字符串),如果您从网站下载最新版本的Node,它将包含ICU。时间戳分辨率您可以将文件的mtime(修改时间)设置为1444291759414(毫秒分辨率),有时会惊讶地发现fs.stat将新的mtime返回为1444291759000(1秒分辨率)或1444291758000(2秒分辨率),这不是节点中的错误。节点返回文件系统存储它的时间戳,并非所有文件系统都支持纳秒、毫秒或1秒时间戳分辨率。一些文件系统甚至对atime时间戳有非常粗略的分辨率,例如某些FAT文件系统为24小时。不要通过规范化文件名和时间戳来破坏文件名和时间戳是用户数据,就像你永远不会自动重写用户文件数据以大写数据或将CRLF规范化为LF行尾一样,所以你不应该通过case/Unicode格式/时间戳规范化要更改、扰乱或损坏文件名或时间戳,规范化只能用于比较,绝不能用于更改数据。规范化实际上是一种有损哈希码,你可以用它来测试某些类型的等价性(例如,几个字符串看起来相同,即使它们有不同的字节序列)但你永远不能用它来代替实际数据,你的程序应该按原样传递文件名和时间戳数据。您的程序可以在NFC(或它喜欢的Unicode形式的任何组合)中创建新数据,或者使用小写或大写文件名,或者使用2秒分辨率时间戳,但您的程序不应该强制大小写/Unicode形式/时间戳规范化来破坏现有的用户数据。相反,采用超集方法并在程序中保留大小写、Unicode格式和时间戳解析,这样您就可以安全地与执行相同操作的文件系统进行交互。正确使用规范化比较函数确保正确使用大小写/Unicode格式/时间戳比较函数,如果您正在处理区分大小写的文件系统,请不要使用不区分大小写的文件名比较函数。如果您正在使用Unicode格式敏感文件系统(例如NTFS和大多数保留NFC和NFD或混合Unicode格式的Linux文件系统),请不要使用Unicode格式不敏感比较函数。如果您使用的是纳秒时间戳分辨率文件系统,请不要比较2秒分辨率的时间戳。为比较功能中的细微差异做好准备。请注意,您的比较函数与文件系统的比较函数相匹配(或者如果可能的话,探测文件系统以查看它实际上是如何比较的),例如不区分大小写比简单的toLowerCase()更复杂,事实上,toUpperCase()通常比toLowerCase()好(因为它以不同方式处理某些外语字符)。但更好的方法是探测文件系统,因为每个文件系统都有自己的案例比较表。例如,Apple的HFS+将文件名规范化为NFD格式,但这种NFD格式实际上是当前NFD格式的旧版本,有时可能与最新Unicode标准的NFD格式略有不同。不要期望HFS+NFD总是与UnicodeNFD完全相同。Previous:HTTP事务剖析Next:流中的背压