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

Pet*_*háč 50 java file

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

boolean OKtoRename(String oldName, String newName)
Run Code Online (Sandbox Code Playgroud)

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

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

if (new File(newName).isFile()) { 
    return false; 
}
Run Code Online (Sandbox Code Playgroud)

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

我在想,有没有一种方法(我知道有没有针对java.io.File的对象)canExist()吗?或者,我将不得不诉诸正则表达式来确保NEWFILE String不包含无效字符(如?,*," :)?我不知道是否有可能是某个地方隐藏在JDK的函数,将一个字符串告诉我可能表示有效的文件名.

Zso*_*rök 58

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

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

编辑: 我想强调,这不是一个完整的解决方案:作为一个评论者指出,即使它通过了这个测试,你的文件名仍然可以是一个Windows特定的关键字,如COM,PRN等.但是,如果你的文件name包含任何这些字符,它肯定会在跨平台环境中造成麻烦.

  • 但是不要忘记关键字,比如尝试创建一个名为COM,COM1,COM2,PRN等的文件(至少在Windows平台上) (12认同)
  • @ZsoltTörök 感谢您的列表。这篇文章可能对那些寻求 Windows 官方文档的人有所帮助:http://support.microsoft.com/kb/177506 (2认同)

eri*_*son 23

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

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

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

这篇相关文章提供了额外的思考:"Java中的移动/复制操作".


更新:

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

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

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

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

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

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

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

但是,这看起来非常糟糕,在其他操作系统上可能不可靠.

  • 但是,您将要删除刚创建的文件,因为函数OKtoRename不应该实际更改文件系统,只需回答文件名是否有效. (2认同)

Max*_*zin 19

这里建议使用系统特定的方法.

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

  • 依赖[不是为工作做的]函数是不是有风险(http://docs.oracle.com/javase/7/docs/api/java/io/File.html#getCanonicalFile()) ? (7认同)
  • 尼斯; 但请注意(即使在Windows上)这并不能理解`file`是(有效)目录名称的情况,例如,以斜杠结尾.如果你想要排除这一点,用`return f.getCanonicalFile().getName().equals(file)`替换第4 + 5行. (7认同)
  • 不错的解决方案,但不幸的是它不适用于 Android :-( iefgetCanonicalPath() 不会因文件名不正确而引发异常 (2认同)

Nic*_* T. 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;
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 这可以通过`org.eclipse.core.resources.IWorkspace.validateName(String,int)`访问 (3认同)