网站首页 > java教程 正文
在本文中,我们将讨论使用 Java 验证一个给定的字符串是否具有操作系统的有效文件名的不同方法。我们可以根据限制的字符或长度限制来检查该值。
我们将只关注核心解决方案,不使用任何外部依赖。我们将使用JDK的java.io和NIO2包来实现我们验证方法。。
使用java.io.File
让我们从第一个例子开始,使用 java.io.File 类。在这个解决方案中,我们需要用一个给定的字符串创建一个File实例,然后在本地磁盘上创建一个文件。
public static boolean validateStringFilenameUsingIO(String filename) throws IOException {
File file = new File(filename);
boolean created = false;
try {
created = file.createNewFile();
return created;
} finally {
if (created) {
file.delete();
}
}
}
当给定的文件名不正确时,它会抛出一个IOException。让我们注意,由于里面的文件创建,这个方法需要给定的文件名字符串没有对应存在的文件。
我们知道,不同的文件系统有自己的文件名限制。通过使用 java.io.File 方法,我们不需要指定每个操作系统的规则,因为Java自动为我们解决了这个问题。
然而,我们需要创建一个假文件。当我们成功后,我们必须记得在最后删除它。此外,我们必须确保我们有适当的权限来执行这些操作。任何失败也可能导致IOException,所以也最好检查一下错误信息。
assertThatThrownBy(() -> validateStringFilenameUsingIO("javanorth?.txt"))
.isInstanceOf(IOException.class)
.hasMessageContaining("Invalid file path");
使用 NIO2 API
我们知道java.io包有很多缺点,因为它是在Java的第一个版本中创建的。NIO2 API是java.io包的后继者,它带来了许多改进,这也大大简化了我们之前的解决方案。
public static boolean validateStringFilenameUsingNIO2(String filename) {
Paths.get(filename);
return true;
}
我们的功能现在被精简了,所以它是进行这种测试的最快方式。我们不创建任何文件,所以我们不需要有任何磁盘权限,也不需要在测试后执行清理。
无效的文件名抛出 nvalidPathException,它扩展了RuntimeException。这个的错误信息也包含了比之前更多的细节。
assertThatThrownBy(() -> validateStringFilenameUsingNIO2(filename))
.isInstanceOf(InvalidPathException.class)
.hasMessageContaining("character not allowed");
但是这个解决方案有一个严重的缺点,与文件系统的限制有关。Path类可能表示带有子目录的文件路径。与第一个例子不同,这个方法没有检查文件名字符的溢出限制。让我们用Apache Commons的randomAlphabetic()方法生成的五百个字符的随机String来检查。
String filename = RandomStringUtils.randomAlphabetic(500);
assertThatThrownBy(() -> validateStringFilenameUsingIO(filename))
.isInstanceOf(IOException.class)
.hasMessageContaining("File name too long");
assertThat(validateStringFilenameUsingNIO2(filename)).isTrue();
为了解决这个问题,我们应该像以前一样,创建一个文件并检查结果。
自定义的实现
最后,让我们尝试实现我们自己的自定义函数来测试文件名。我们还将尝试避免任何I/O功能,只使用核心的Java方法。
这类解决方案提供了更多的控制权,允许我们实现我们自己的规则。然而,我们必须考虑不同系统的许多额外限制。
使用String.contains
我们可以使用String.contains()方法来检查给定的String是否包含任何禁止的字符。首先,我们需要手动指定一些示例值。
public static final Character[] INVALID_WINDOWS_SPECIFIC_CHARS = {'"', '`', '<', '>', '?', '|'};
public static final Character[] INVALID_UNIX_SPECIFIC_CHARS = {'\000'};
在我们的例子中,让我们只关注这两个操作系统,Windows的文件名比UNIX的限制更多。另外,一些的空白字符可能会有问题。
在定义了受限制的字符集之后,让我们来确定当前的操作系统。
public static Character[] getInvalidCharsByOS() {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
return INVALID_WINDOWS_SPECIFIC_CHARS;
} else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) {
return INVALID_UNIX_SPECIFIC_CHARS;
} else {
return new Character[]{};
}
}
而现在我们可以用它来测试给定的值。
public static boolean validateStringFilenameUsingContains(String filename) {
if (filename == null || filename.isEmpty() || filename.length() > 255) {
return false;
}
return Arrays.stream(getInvalidCharsByOS())
.noneMatch(ch -> filename.contains(ch.toString()));
}
如果我们定义的任何字符不在给定的文件名中,这个Stream谓词返回真。此外,我们还实现了对null值和不正确长度的支持。
正则表达式模式匹配
我们也可以在给定的String上直接使用正则表达式。让我们来实现一个只接受字母数字和点字符的模式,其长度不超过255。
public static final String REGEX_PATTERN = "^[A-za-z0-9.]{1,255}#34;;
public static boolean validateStringFilenameUsingRegex(String filename) {
if (filename == null) {
return false;
}
return filename.matches(REGEX_PATTERN);
}
现在,我们可以根据先前准备的模式测试给定的值。我们还可以轻松地修改模式。在这个例子中,我们跳过了操作系统的检查功能。
总结
在这篇文章中,我们集中讨论了文件名及其限制。我们介绍了不同的算法,用Java检测无效的文件名。
我们从java.io包开始,它为我们解决了大部分的系统限制,但执行了额外的I/O动作,可能需要一些权限。然后我们检查了NIO2 API,它是最快的解决方案,但有文件名长度检查的限制。
最后,我们实现了我们自己的方法,不使用任何I/O API,但需要自定义实现文件系统规则。
猜你喜欢
- 2024-10-06 一文搞定java.lang.Class.isInstance和instanceof的区别
- 2024-10-06 如何使用Java 文件系统 File类?(java files类)
- 2024-10-06 Spring问题之提示文件不存在处理it does not exist
- 2024-10-06 Java中类加载器的工作原理(java中类加载器有几种)
- 2024-10-06 java常见问题(java常见问题及答案)
- 2024-10-06 「Java」常用的文件操作(java 文件处理)
- 2024-10-06 JAVA中的文件操作2-如何读写文件(java高并发读写文件)
- 2024-10-06 bitmap算法:如何在20亿个非负整数中如何判断一个数是否存在?
- 2024-10-06 java中读取properties文件最简单的方法
- 2024-10-06 五十六、探析Java文件过滤技术与高级文件检索方法
你 发表评论:
欢迎- 最近发表
-
- 你真的会用 Java 中的线程池吗?多个企业级线程池工具类封装实践
- 线程池的实现原理、优点与风险、以及四种线程池实现
- Java线程池ThreadPoolExecutor实现原理剖析
- 深入分析线程池的实现原理(线程池是干嘛的)
- 一文搞懂JAVA线程池工作原理(java线程池的工作流程)
- Java线程池的工作原理(java线程池的实现原理)
- 5分钟读懂C#中TcpClient、TcpListener和Socket三个类的角色
- JVM对象的创建过程(jvm运行过程中创建的对象一般存放在方法区)
- 对象组成与Java内存模型JMM分析(java对象在内存中存储的结构)
- JVM对象内存分配详细过程(栈上分配->TLAB->老年代->Eden区)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)