如果我想安全地尝试在 D 中打开文件,则首选方法是
- 尝试打开它,如果它失败,则捕获异常(并可选择找出原因)或
- 检查它是否存在,是否可读,然后才打开它
我猜第二种选择会导致更多的 IO 并且更复杂,对吧?
如果根据正常的程序操作和给定的用户输入预期文件存在,则使用 1 - 尝试打开文件并依靠异常处理来处理文件不存在的异常情况。
例如:
/// If the user has a local configuration file in his home directory, open that.
/// Otherwise, open the global configuration file that is a part of the program,
/// and should be installed on all systems where the program is running.
File configFile;
if ("~/.transmogrifier.conf".expandTilde.exists)
configFile.open("~/.transmogrifier.conf".expandTilde);
else
configFile.open("/etc/transmogrifier.conf");
请注意,使用 2 可能会导致程序中出现安全问题。例如,如果在您的程序检查文件是否存在时文件存在,但在尝试打开它时却消失了,则您的程序可能会以意想不到的方式运行。如果您使用 2,请确保在打开文件失败时您的程序仍能以理想的方式运行,即使您的程序刚刚检查了该文件是否存在并且可读。
我想说你需要准备好无论如何都会抛出异常,否则你有一个竞争条件(另一个进程可能会删除测试和打开等之间的文件)。所以最好还是先打开,然后处理突发事件。
一般来说,最好先检查文件是否存在,因为文件不存在的可能性很大,而只是在尝试打开时让它失败,这是使用异常进行流控制的情况。在文件不存在的情况下效率也很低,因为 D 中的异常非常昂贵(尽管 I/O 的成本可能仍然超过异常的成本,因为 I/O 的成本很高)。
在可能引发异常的情况下使用异常通常被认为是不好的做法。在这些情况下,最好返回操作是否成功,或者在尝试操作之前检查操作是否可能成功。在打开文件的情况下,您可能会执行后者。所以,做你想做的事情的最干净的方法是做类似的事情
if(filename.exists)
{
auto file = File(filename);
...
}
或者,如果您想一次性将整个文件作为字符串读取,您可以
if(filename.exists)
{
auto fileContents = readText(filename);
...
}
exists
并且readText
在 std.file 中,并且File
在 std.stdio 中。
如果您正在处理文件很可能存在并且因此不太可能引发异常的情况,那么跳过检查并尝试打开文件就可以了。但是您要避免的是依赖于在操作不太可能失败时抛出的异常。您希望很少抛出异常,因此在尝试操作之前检查操作是否会成功,如果它们可能会失败并抛出异常。否则,您最终会使用异常来进行流控制并损害程序的效率(和可维护性)。
通常情况下,当您尝试打开文件时文件不存在,因此通常情况下您应该在尝试打开文件之前检查文件是否存在(但这最终取决于您的特定用例) .