Java - 如何找出文件名是否有效?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/893977/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:46:36  来源:igfitidea点击:

Java - How to find out whether a File name is valid?

javafile

提问by Peter Perhá?

In my Java application I am renaming files to a file name provided in a String parameter. There is a method

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

boolean OKtoRename(String oldName, String newName)

which basically checks whether the newName isn't already taken by some other file, as I wouldn't want to bury existing ones.

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

It now occurred to me that perhaps the newName String will not denote a valid file name. So I thought to add this check to the method:

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

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

Which obviously isn't the right way to do it, since in most cases the newFile does not yet exist and therefore although it isOKtoRename, the function returns false.

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

I was wondering, is there a method (I know there isn't for the java.io.File objects) like canExist()? Or would I have to resort to regex to make sure the newFile String does not contain invalid characters (e.g. ?, *, ", :)? I wonder if there is perhaps a function hidden somewhere in the JDK that would tell me if a string could possibly denote a valid file name.

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

采纳答案by erickson

Use createNewFile(), which will atomically create the file only if it doesn't yet exist.

使用createNewFile(),它只会在文件不存在时自动创建文件。

If the file is created, the name is valid and it is not clobbering an existing file. You can then open the files and efficiently copy data from one to the other with FileChannel.transferXXXoperations.

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

An important thing to keep in mind that, in general, the check and the creation should be atomic. If you first check whether an operation is safe, then perform the operation as a separate step, conditions may have changed in the meantime, making the operation unsafe.

要记住的一件重要事情是,一般来说,检查和创建应该是原子的。如果首先检查操作是否安全,然后将操作作为单独的步骤执行,在此期间条件可能已发生变化,从而使操作变得不安全。

Additional food for thought is available at this related post: "Move/Copy operations in Java."

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



Update:

更新:

Since this answer, the NIO.2 APIs have been introduced, which add more interaction with the file system.

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

Suppose you have an interactive program, and want to validate after each keystroke whether the file is potentially valid. For example, you might want to enable a "Save" button only when the entry is valid rather than popping up an error dialog after pressing "Save". Creating and ensuring the deletion of a lot of unnecessary files that my suggestion above would require seems like a mess.

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

With NIO.2, you can't create a Pathinstance containing characters that are illegal for the file system. An InvalidPathExceptionis raised as soon as you try to create the Path.

使用 NIO.2,您无法创建Path包含对文件系统非法的字符的实例。一InvalidPathException,当你试图创建即将提出的Path

However, there isn't an API to validate illegal names comprised of valid characters, like "PRN" on Windows. As a workaround, experimentation showed that using an illegal file name would raise a distinct exception when trying to access attributes (using Files.getLastModifiedTime(), for example).

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

If you specify a legal name for a file that does exist, you get no exception.

如果为确实存在的文件指定合法名称,则不会有任何例外。

If you specify a legal name for a file that does not exist, it raises NoSuchFileException.

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

If you specify an illegal name, FileSystemExceptionis raised.

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

However, this seems very kludgey and might not be reliable on other operating systems.

但是,这看起来很笨拙,在其他操作系统上可能不可靠。

回答by Zsolt T?r?k

I assembled a list of illegal filename characters (considering UNIX, Mac OS X and Windows systems) based on some online research a couple of months ago. If the new filename contains any of these, there's a risk that it might not be valid on all platforms.

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

private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '
String validName = URLEncoder.encode( fileName , "UTF-8");

File newFile = new File( validName );
', '\f', '`', '?', '*', '\', '<', '>', '|', '\"', ':' };

EDIT:I would like to stress, that this is not a complete solution: as a commenter pointed out, even though it passes this test your file name could still be a Windows specific keyword like COM, PRN, etc. However, if your file name contains any of these characters, it will certainly cause trouble in a cross-platform environment.

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

回答by svachon

To me it appears to be an OS dependent problem. You may simply want to check for some invalid character in the file name. Windows does this when you try to rename the file, it pops a message saying that a file cannot contain any of the following characters: \ / : * ? < > | I am not sure if your question is "is there a library doing the job for me?" in that case I don't know any.

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

回答by OscarRyz

Using

使用

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

Does the work.

工作。

I have just found today. I'm not sure if it works 100% of the time, but so far, I have been able to create valid file names.

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

回答by Mosty Mostacho

This is how I implemented this:

这就是我实现的方式:

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

回答by Maxim Mazin

Heresystem specific way is suggested.

这里建议系统特定的方式。

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[] {'/', '##代码##',};
         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;
   }
}

回答by Nick J. R. T.

If developing for Eclipse, check out org.eclipse.core.internal.resources.OS

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

##代码##

回答by BrainStorm.exe

Just something i found, in java 7 and later, there is a class called Pathsthat has a method called getthat takes one or more Strings and throws

只是我发现的东西,在 java 7 及更高版本中,有一个名为的类Paths,它有一个调用的方法get,它接受一个或多个Strings 并抛出

InvalidPathException- if the path string cannot be converted to a Path

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