如何在linux中两次打开文件?

时间:2015-12-04 21:59:11

标签: c linux file system-calls stat

我有一个带有fd和字符串的链表我用来在每个条目中打开这个文件。我想打开并仅在此文件尚未打开的情况下将文件添加到此列表中,因为我打开并解析此文件并且不想两次执行此操作。我的想法是将文件名与此列表中的每个名称进行比较,但我的程序多次执行,Linux中的一个文件可以有多个名称(软/硬链接)。我认为它不应该那么复杂,因为操作系统很容易检查,我是否已经使用了inode,r? 我已经尝试open使用flock和不使用fd的同一个文件,但我总是得到一个新的$("li.menuContainer > a.top").click(function(e) { e.preventDefault(); $div = $(this).next("div.sub"); $("li.menuContainer div.sub").not($div).slideUp(); $div.slideDown(); });

3 个答案:

答案 0 :(得分:7)

成功打开文件后,请在文件中使用fstat。检查st_ino提交的st_dev的{​​{1}}和fstat是否已记录在您的链接列表中。如果是,则关闭文件描述符并继续下一个文件。否则,将文件描述符,文件名以及st_inost_dev值添加到列表中。

您可以在打开文件之前使用struct stat进行检查,但如果通常情况下该文件尚未打开,则使用fstat后会稍快一些。

答案 1 :(得分:1)

在这种情况下,考虑您的数据结构通常很有用。更改为不允许重复的数据结构,例如哈希表。

维护一组您之前见过的数据。我为这套使用了hash table。根据{{​​3}},使用inode和设备作为密钥。这允许在O(1)时间内发现重复。

以下是一个示例实现。

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>

static int get_fd(GHashTable *fds, const char *filename, int mode) {
    int fd;
    struct stat stat;
    int keysize = 33;
    char key[keysize];  /* Two 64 bit numbers as hex and a separator */

    /* Resolve any symlinks */
    char *real_filename = realpath(filename, NULL);
    if( real_filename == NULL ) {
        printf("%s could not be resolved.\n", filename);
        return -1;
    }

    /* Open and stat */
    fd = open( real_filename, mode );
    if( fd < 0 ) {
        printf("Could not open %s: %s.\n", real_filename, strerror(errno));
        return -1;
    }
    if( fstat(fd, &stat) != 0 ) {
        printf("Could not stat %s: %s.\n", real_filename, strerror(errno));
        return -1;
    }

    /* Make a key for tracking which data we've processed.
       This uses both the inode and the device it's on.
       It could be done more efficiently as a bit field.
     */
    snprintf(key, keysize, "%lx|%lx", (long int)stat.st_ino, (long int)stat.st_dev);

    /*  See if we've already processed that */
    if( g_hash_table_contains(fds, key) ) {
        return 0;
    }
    else {
        /* Note that we've processed it */
        g_hash_table_add(fds, key);
        return fd;
    }
}


int main(int argc, char** argv) {
    int mode = O_RDONLY;
    int fd;
    GHashTable *fds = g_hash_table_new(&g_str_hash, &g_str_equal);

    for(int i = 1; i < argc; i++) {
        char *filename = argv[i];

        fd = get_fd(fds, filename, mode);
        if( fd == 0 ) {
            printf("%s has already been processed.\n", filename);
        }
        else if( fd < 0 ) {
            printf("%s could not be processed.\n", filename);
        }
        else {
            printf("%s: %d\n", filename, fd);
        }
    }
}

这是一个示例结果。

$ touch one two three
$ ln one one_link
$ ln -s two two_sym
$ ./test one* two* three*
one: 3
one_link has already been processed.
two: 5
two_sym has already been processed.
three: 7

答案 2 :(得分:-1)

只要您不关闭成功和有意打开的文件,就可以使用非阻止flock来阻止对同一文件的另一次锁定:

#include <unistd.h>
#include <sys/file.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <assert.h>

int openAndLock(const char* fn){
  int fd = -1;
  if(((fd = open(fn, O_RDONLY)) >= 0) && (flock(fd, LOCK_EX|LOCK_NB) == 0)){
      fprintf(stderr, "Successfully opened and locked %s\n", fn);
      return fd;
  }else{
    fprintf(stderr, "Failed to open or lock %s\n", fn);
    close(fd);
    return -1;
  }
}

int main(int argc, char** argv){
  for(int i=1; i<argc; i++){
    openAndLock(argv[i]);
  }
  return 0;
}

示例:

$ touch foo
$ ln foo bar
$ ./a.out foo foo
Successfully opened and locked foo
Failed to open or lock foo
$ ./a.out foo bar
Successfully opened and locked foo
Failed to open or lock bar