Java - 如何确定文件名是否有效?

时间:2009-05-21 17:04:46

标签: java file

在我的Java应用程序中,我将文件重命名为String参数中提供的文件名。有一种方法

boolean OKtoRename(String oldName, String newName)

基本上检查newName是否已被其他文件占用,因为我不想埋没现有文件。

现在我想到,newName String可能不会表示有效的文件名。所以我想把这个检查添加到方法中:

if (new File(newName).isFile()) { 
    return false; 
}

这显然不是正确的方法,因为在大多数情况下newFile尚不存在,因此虽然 OKtoRename,但该函数返回false。

我想知道,有没有像canExist()这样的方法(我知道java.io.File对象没有)?或者我是否必须使用正则表达式来确保newFile String不包含无效字符(例如?,*,“,:)?我想知道是否有一个函数隐藏在JDK的某个地方会告诉我是否有字符串可能表示有效的文件名。

8 个答案:

答案 0 :(得分:58)

我在几个月前根据一些在线研究汇总了非法文件名字符列表(考虑UNIX,Mac OS X和Windows系统)。如果新文件名包含其中任何一个,则存在在所有平台上可能无效的风险。

private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' };

修改 我想强调,这是不是一个完整的解决方案:正如评论者指出的那样,即使通过此测试,您的文件名仍可能是Windows特定的关键字,如COM,PRN等。但是,如果您的文件名包含任何这些字符,那么它肯定会在跨平台环境中造成麻烦。

答案 1 :(得分:23)

使用createNewFile(),只有当文件尚不存在时才会自动创建文件。

如果创建了文件,则该名称有效且不会破坏现有文件。然后,您可以使用FileChannel.transferXXX操作打开文件并有效地将数据从一个复制到另一个。

重要的是要记住,一般来说,检查和创建应该是原子的。如果您首先检查操作是否安全,则作为单独的步骤执行操作,同时条件可能已更改,从而使操作不安全。

此相关帖子提供了额外的思考:"Move/Copy operations in Java."


更新

由于这个答案,我们引入了NIO.2 API,它们增加了与文件系统的更多交互。

假设您有一个交互式程序,并希望在每次击键后验证该文件是否可能有效。例如,您可能只想在条目有效时启用“保存”按钮,而不是在按“保存”后弹出错误对话框。创建并确保删除我上面建议的许多不必要的文件似乎是一团糟。

使用NIO.2,您无法创建包含对文件系统非法的字符的Path实例。尝试创建InvalidPathException时会引发Path

但是,没有用于验证由有效字符组成的非法名称的API,例如Windows上的“PRN”。作为一种解决方法,实验表明,在尝试访问属性时,使用非法文件名会引发一个明显的异常(例如,使用Files.getLastModifiedTime())。

如果为存在的文件指定合法名称,则不会出现异常。

如果为不存在的文件指定合法名称,则会引发NoSuchFileException

如果您指定了非法名称,则会引发FileSystemException

然而,这看起来非常糟糕,在其他操作系统上可能不可靠。

答案 2 :(得分:18)

建议使用

Here系统特定方式。

public static boolean isFilenameValid(String file) {
  File f = new File(file);
  try {
    f.getCanonicalPath();
    return true;
  } catch (IOException e) {
    return false;
  }
}

答案 3 :(得分:6)

如果要开发Eclipse,请查看org.eclipse.core.internal.resources.OS

public abstract class OS {
   private static final String INSTALLED_PLATFORM;

   public static final char[] INVALID_RESOURCE_CHARACTERS;
   private static final String[] INVALID_RESOURCE_BASENAMES;
   private static final String[] INVALID_RESOURCE_FULLNAMES;

   static {
      //find out the OS being used
      //setup the invalid names
      INSTALLED_PLATFORM = Platform.getOS();
      if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) {
         //valid names and characters taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp
         INVALID_RESOURCE_CHARACTERS = new char[] {'\\', '/', ':', '*', '?', '"', '<', '>', '|'};
         INVALID_RESOURCE_BASENAMES = new String[] {"aux", "com1", "com2", "com3", "com4", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 
               "com5", "com6", "com7", "com8", "com9", "con", "lpt1", "lpt2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
               "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "nul", "prn"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
         Arrays.sort(INVALID_RESOURCE_BASENAMES);
         //CLOCK$ may be used if an extension is provided
         INVALID_RESOURCE_FULLNAMES = new String[] {"clock$"}; //$NON-NLS-1$
      } else {
         //only front slash and null char are invalid on UNIXes
         //taken from http://www.faqs.org/faqs/unix-faq/faq/part2/section-2.html
         INVALID_RESOURCE_CHARACTERS = new char[] {'/', '\0',};
         INVALID_RESOURCE_BASENAMES = null;
         INVALID_RESOURCE_FULLNAMES = null;
      }
   }

   /**
    * Returns true if the given name is a valid resource name on this operating system,
    * and false otherwise.
    */
   public static boolean isNameValid(String name) {
      //. and .. have special meaning on all platforms
      if (name.equals(".") || name.equals("..")) //$NON-NLS-1$ //$NON-NLS-2$
         return false;
      if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) {
         //empty names are not valid
         final int length = name.length();
         if (length == 0)
            return false;
         final char lastChar = name.charAt(length-1);
         // filenames ending in dot are not valid
         if (lastChar == '.')
            return false;
         // file names ending with whitespace are truncated (bug 118997)
         if (Character.isWhitespace(lastChar))
            return false;
         int dot = name.indexOf('.');
         //on windows, filename suffixes are not relevant to name validity
         String basename = dot == -1 ? name : name.substring(0, dot);
         if (Arrays.binarySearch(INVALID_RESOURCE_BASENAMES, basename.toLowerCase()) >= 0)
            return false;
         return Arrays.binarySearch(INVALID_RESOURCE_FULLNAMES, name.toLowerCase()) < 0;
      }
      return true;
   }
}

答案 4 :(得分:4)

这是我实现这个的方式:

public boolean isValidFileName(final String aFileName) {
    final File aFile = new File(aFileName);
    boolean isValid = true;
    try {
        if (aFile.createNewFile()) {
            aFile.delete();
        }
    } catch (IOException e) {
        isValid = false;
    }
    return isValid;
}

答案 5 :(得分:3)

对我来说,这似乎是一个依赖操作系统的问题。您可能只想检查文件名中的某些无效字符。当您尝试重命名文件时Windows会执行此操作,它会弹出一条消息,指出文件不能包含以下任何字符:\ /:*? &LT; &GT; | 我不确定你的问题是“是否有图书馆为我做这个工作?”在那种情况下,我不知道。

答案 6 :(得分:3)

我发现,在java 7及更高版本中,有一个名为Paths的类,它有一个名为get的方法,它接受一个或多个String s并抛出

  

InvalidPathException - 如果路径字符串无法转换为路径

答案 7 :(得分:0)

使用

String validName = URLEncoder.encode( fileName , "UTF-8");

File newFile = new File( validName );

是否有效。

我今天刚刚找到。我不确定它是否100%有效,但到目前为止,我已经能够创建有效的文件名。