5

我们想写入给定目录中的“foo.txt”。如果“foo.txt”已经存在,我们要写入“foo-1.txt”,以此类推。

有一些代码片段试图回答这个问题,但没有一个是非常令人满意的。例如,CocoaDev 的这个解决方案使用 NSFileManager 来测试路径是否存在以创建安全路径。但是,这会导致获取路径和写入路径之间出现明显的竞争条件。尝试原子写入会更安全,并在失败时循环数字后缀。

去吧!

4

3 回答 3

1

使用带有和选项的open系统调用。如果文件不存在,将创建它,打开它,并将文件描述符返回给您;如果确实存在,将失败并设置为.O_EXCLO_CREATopenopenerrnoEEXIST

从那里,应该很明显如何构造循环尝试递增文件名,直到它返回文件描述符或构造太长的文件名。在后一点上,请确保您检查errno失败的open时间——<code>EEXIST,ENAMETOOLONG这只是您可能遇到的两个错误。

于 2009-04-21T02:09:59.803 回答
1
int fd;
uint32_t counter;
char filename[1024]; // obviously unsafe

sprintf(filename, "foo.txt");
if( (fd = open(filename, O_CREAT | O_EXCL | O_EXLOCK, 0644)) == -1 && errno == EEXIST ) 
{
    for( counter = 1; counter < UINT32_MAX; counter++ ) {
      sprintf(filename, "foo-%u.txt", counter);
      if( (fd = open(filename, O_CREAT | O_EXCL | O_EXLOCK, 0644)) == -1 && errno == EEXIST )
        continue;
      else
        break;
    }
}

if( fd == -1 && counter == UINT32_MAX ) {
    fprintf(stderr, "too many foo-files\n");
} else if( fd == -1 ) {
    fprintf(stderr, "could not open file: %s\n", strerror(errno));
}

// otherwise fd is an open file with an atomically unique name and an
// exclusive lock.
于 2009-04-21T02:25:22.247 回答
1

怎么样:

  1. 将文件写入您知道没有冲突风险的临时目录
  2. 使用 NSFileManager 将文件移动到首选目的地
  3. 如果步骤 3 由于文件已存在而失败,请添加/增加数字后缀并重复步骤 2

您将基本上重新创建 Cocoa 的原子文件写入处理,但添加了确保唯一文件名的功能。这种方法的一大优点是,如果断电或您的应用程序在写入过程中崩溃,半成品文件将被隐藏在 tmp 文件夹中并被系统删除;没有留给用户尝试和使用。

于 2009-04-21T09:06:54.013 回答