这个问题在这里已经有答案了:

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

boolean OKtoRename(String oldName, String newName)

它基本上检查 newName 是否尚未被其他文件占用,因为我不想埋葬现有的文件。

现在我想到,也许 newName 字符串不会表示有效的文件名。所以我想将这个检查添加到方法中:

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

这显然不是正确的方法,因为在大多数情况下 newFile 还不存在,因此尽管它 OKtoRename,函数返回false。

我想知道,是否有一种方法(我知道没有 java.io.File 对象),例如 canExist()?或者我是否必须诉诸正则表达式来确保 newFile 字符串不包含无效字符(例如?、*、"、:)?我想知道 JDK 中是否隐藏着一个函数,可以告诉我一个字符串是否可以表示有效的文件名。

有帮助吗?

解决方案

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

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

需要记住的重要一点是,一般来说,检查和创建应该是原子的。如果您首先检查操作是否安全,然后作为单独的步骤执行该操作,则条件可能会同时发生变化,从而导致操作不安全。

这篇相关文章中提供了更多值得深思的内容: “Java 中的移动/复制操作。”


更新:

自这个答案以来,NIO.2 API 被引入,它增加了与文件系统的更多交互。

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

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

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

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

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

如果您指定非法名称, FileSystemException 被提出。

然而,这看起来非常笨拙,并且在其他操作系统上可能不可靠。

其他提示

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

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

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

这里 建议系统特定方式。

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

如果针对 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;
   }
}

这就是我的实现方式:

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;
}

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

只是我发现,在 java 7 及更高版本中,有一个名为 Paths 有一个名为的方法 get 这需要一个或多个 Strings 和抛出

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

使用

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

File newFile = new File( validName );

做工作。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top