有没有办法在Java中确定路径是否有效而不尝试创建文件?

时间:2009-01-22 11:39:27

标签: java validation filesystems

我需要确定用户提供的字符串是否是有效的文件路径(即,如果createNewFile()将成功或抛出异常)但我不想使用无用的文件膨胀文件系统,仅用于验证目的。

有没有办法确定我拥有的字符串是否是有效的文件路径而不尝试创建文件?

我知道“有效文件路径”的定义因操作系统而异,但我想知道是否有任何快捷的方法可以接受C:/foo/foo并拒绝banana

一种可能的方法可能是尝试创建文件并最终在创建成功时删除它,但我希望有更优雅的方法来实现相同的结果。

7 个答案:

答案 0 :(得分:28)

这也会检查目录是否存在。

File file = new File("c:\\cygwin\\cygwin.bat");
if (!file.isDirectory())
   file = file.getParentFile();
if (file.exists()){
    ...
}

如果您有权写入目录,似乎file.canWrite()不会给您一个明确的指示。

答案 1 :(得分:26)

Java 7中引入的Path类添加了新的替代方案,如下所示:
Linux 下正常工作 - 总是返回true)

/**
 * <pre>
 * Checks if a string is a valid path.
 * Null safe.
 *  
 * Calling examples:
 *    isValidPath("c:/test");      //returns true
 *    isValidPath("c:/te:t");      //returns false
 *    isValidPath("c:/te?t");      //returns false
 *    isValidPath("c/te*t");       //returns false
 *    isValidPath("good.txt");     //returns true
 *    isValidPath("not|good.txt"); //returns false
 *    isValidPath("not:good.txt"); //returns false
 * </pre>
 */
public static boolean isValidPath(String path) {
    try {
        Paths.get(path);
    } catch (InvalidPathException | NullPointerException ex) {
        return false;
    }
    return true;
}

答案 2 :(得分:16)

File.getCanonicalPath()对此非常有用。在解析操作系统或文件系统时,某些类型的无效文件名(例如Windows中的CONPRN*?*)会抛出IO异常。但是,这仅作为初步检查;在实际创建文件时,您仍需要处理其他故障(例如权限不足,缺少驱动器空间,安全限制)。

答案 3 :(得分:15)

尝试创建文件时可能会出现许多问题:

  • 您缺少必要的权限;
  • 设备上没有足够的空间;
  • 设备遇到错误;
  • 某些自定义安全策略禁止您创建特定类型的文件;

更重要的是,这些可以在您尝试和查询之间进行更改,以确定您是否可以以及何时可以实现。在多线程环境中,这是竞争条件的主要原因之一,并且可能是某些程序的真正漏洞。

基本上你只需要尝试创建它,看它是否有效。这是正确的方法。这就是为什么像ConcurrentHashMap这样的东西有一个putIfAbsent()所以检查和插入是一个原子操作,并且不会受到竞争条件的影响。完全相同的原则在这里发挥作用。

如果这只是某些诊断或安装过程的一部分,请执行此操作并查看其是否有效。但是,不能保证它会在以后工作。

基本上,如果程序无法编写相关文件,那么你的程序必须足够健壮才能优雅地存在。

答案 4 :(得分:0)

您可以在某些操作系统上执行此操作

使用正则表达式匹配来检查现有的已知无效字符。

if (newName.matches(".*[/\n\r\t\0\f`?*\\<>|\":].*")) {
    System.out.println("Invalid!");
} else {
    System.out.println("Valid!");
}

专业人士

  • 这适用于所有操作系统
  • 您可以通过任何方式自定义 您需要通过编辑该正则表达式来实现。

缺点

  • 这可能不是一个完整的列表,需要更多的研究来填写更多无效的模式或字符。

答案 5 :(得分:0)

只需这样做(然后自己清理)

  

一种可能的方法可能是尝试创建文件,如果创建成功,则最终将其删除,但是我希望有一种更优雅的方法来实现相同的结果。

也许这是最可靠的方法。

下面是canCreateOrIsWritable,它确定您的程序是否能够在给定的路径上创建文件及其父目录,或者如果已经存在文件,则对其进行写入。

通过实际创建必要的父目录以及路径中的空文件来实现。之后,它将删除它们(如果路径中存在文件,则将其保留)。

这是您的使用方式:

var myFile = new File("/home/me/maybe/write/here.log")

if (canCreateOrIsWritable(myFile)) {
    // We're good. Create the file or append to it
    createParents(myFile);
    appendOrCreate(myFile, "new content");
} else {
    // Let's pick another destination. Maybe the OS's temporary directory:
    var tempDir = System.getProperty("java.io.tmpdir");
    var alternative = Paths.get(tempDir, "second_choice.log");
    appendOrCreate(alternative, "new content in temporary directory");
}

一些辅助方法的基本方法:

static boolean canCreateOrIsWritable(File file) {
    boolean canCreateOrIsWritable;

    // The non-existent ancestor directories of the file.
    // The file's parent directory is first
    List<File> parentDirsToCreate = getParentDirsToCreate(file);

    // Create the parent directories that don't exist, starting with the one
    // highest up in the file system hierarchy (closest to root, farthest
    // away from the file)
    reverse(parentDirsToCreate).forEach(File::mkdir);

    try {
        boolean wasCreated = file.createNewFile();
        if (wasCreated) {
            canCreateOrIsWritable = true;
            // Remove the file and its parent dirs that didn't exist before
            file.delete();
            parentDirsToCreate.forEach(File::delete);
        } else {
            // There was already a file at the path → Let's see if we can
            // write to it
            canCreateOrIsWritable = java.nio.file.Files.isWritable(file.toPath());
        }
    } catch (IOException e) {
        // File creation failed
        canCreateOrIsWritable = false;
    }
    return canCreateOrIsWritable;
}

static List<File> getParentDirsToCreate(File file) {
    var parentsToCreate = new ArrayList<File>();
    File parent = file.getParentFile();
    while (parent != null && !parent.exists()) {
        parentsToCreate.add(parent);

        parent = parent.getParentFile();
    }
    return parentsToCreate;
}

static <T> List<T> reverse(List<T> input) {
    var reversed = new ArrayList<T>();
    for (int i = input.size() - 1; i >= 0; i--) {
        reversed.add(input.get(i));
    }
    return reversed;
}

static void createParents(File file) {
    File parent = file.getParentFile();
    if (parent != null) {
        parent.mkdirs();
    }
}

请记住,在调用canCreateOrIsWritable与创建实际文件之间,文件系统的内容和权限可能已更改。

答案 6 :(得分:-1)

boolean canWrite(File file) {
  if (file.exists()) {
    return file.canWrite();
  }
  else {
    try {
      file.createNewFile();
      file.delete();
      return true;
    }
    catch (Exception e) {
      return false;
    }
  }
}