在本文中,我們將討論使用 Java 驗(yàn)證一個(gè)給定的字符串是否具有操作系統(tǒng)的有效文件名的不同方法。我們可以根據(jù)限制的字符或長(zhǎng)度限制來檢查該值。
我們將只關(guān)注核心解決方案,不使用任何外部依賴。我們將使用JDK的java.io
和NIO2包來實(shí)現(xiàn)我們驗(yàn)證方法。。
使用java.io.File
讓我們從第一個(gè)例子開始,使用 java.io.File
類。在這個(gè)解決方案中,我們需要用一個(gè)給定的字符串創(chuàng)建一個(gè)File
實(shí)例,然后在本地磁盤上創(chuàng)建一個(gè)文件。
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();
}
}
}
當(dāng)給定的文件名不正確時(shí),它會(huì)拋出一個(gè)IOException
。讓我們注意,由于里面的文件創(chuàng)建,這個(gè)方法需要給定的文件名字符串沒有對(duì)應(yīng)存在的文件。
我們知道,不同的文件系統(tǒng)有自己的文件名限制。通過使用 java.io.File
方法,我們不需要指定每個(gè)操作系統(tǒng)的規(guī)則,因?yàn)镴ava自動(dòng)為我們解決了這個(gè)問題。
然而,我們需要?jiǎng)?chuàng)建一個(gè)假文件。當(dāng)我們成功后,我們必須記得在最后刪除它。此外,我們必須確保我們有適當(dāng)?shù)臋?quán)限來執(zhí)行這些操作。任何失敗也可能導(dǎo)致IOException
,所以也最好檢查一下錯(cuò)誤信息。
assertThatThrownBy(() - > validateStringFilenameUsingIO("javanorth?.txt"))
.isInstanceOf(IOException.class)
.hasMessageContaining("Invalid file path");
使用 NIO2 API
我們知道java.io
包有很多缺點(diǎn),因?yàn)樗窃贘ava的第一個(gè)版本中創(chuàng)建的。NIO2 API是java.io
包的后繼者,它帶來了許多改進(jìn),這也大大簡(jiǎn)化了我們之前的解決方案。
public static boolean validateStringFilenameUsingNIO2(String filename) {
Paths.get(filename);
return true;
}
我們的功能現(xiàn)在被精簡(jiǎn)了,所以它是進(jìn)行這種測(cè)試的最快方式。我們不創(chuàng)建任何文件,所以我們不需要有任何磁盤權(quán)限,也不需要在測(cè)試后執(zhí)行清理。
無效的文件名拋出 nvalidPathException
,它擴(kuò)展了RuntimeException
。這個(gè)的錯(cuò)誤信息也包含了比之前更多的細(xì)節(jié)。
assertThatThrownBy(() - > validateStringFilenameUsingNIO2(filename))
.isInstanceOf(InvalidPathException.class)
.hasMessageContaining("character not allowed");
但是這個(gè)解決方案有一個(gè)嚴(yán)重的缺點(diǎn),與文件系統(tǒng)的限制有關(guān)。Path
類可能表示帶有子目錄的文件路徑。與第一個(gè)例子不同,這個(gè)方法沒有檢查文件名字符的溢出限制。讓我們用Apache Commons的randomAlphabetic()
方法生成的五百個(gè)字符的隨機(jī)String
來檢查。
String filename = RandomStringUtils.randomAlphabetic(500);
assertThatThrownBy(() - > validateStringFilenameUsingIO(filename))
.isInstanceOf(IOException.class)
.hasMessageContaining("File name too long");
assertThat(validateStringFilenameUsingNIO2(filename)).isTrue();
為了解決這個(gè)問題,我們應(yīng)該像以前一樣,創(chuàng)建一個(gè)文件并檢查結(jié)果。
自定義的實(shí)現(xiàn)
最后,讓我們嘗試實(shí)現(xiàn)我們自己的自定義函數(shù)來測(cè)試文件名。我們還將嘗試避免任何I/O功能,只使用核心的Java方法。
這類解決方案提供了更多的控制權(quán),允許我們實(shí)現(xiàn)我們自己的規(guī)則。然而,我們必須考慮不同系統(tǒng)的許多額外限制。
使用String.contains
我們可以使用String.contains()
方法來檢查給定的String
是否包含任何禁止的字符。首先,我們需要手動(dòng)指定一些示例值。
public static final Character[] INVALID_WINDOWS_SPECIFIC_CHARS = {'"', '`', '< ', ' >', '?', '|'};
public static final Character[] INVALID_UNIX_SPECIFIC_CHARS = {'?00'};
在我們的例子中,讓我們只關(guān)注這兩個(gè)操作系統(tǒng),Windows的文件名比UNIX的限制更多。另外,一些的空白字符可能會(huì)有問題。
在定義了受限制的字符集之后,讓我們來確定當(dāng)前的操作系統(tǒng)。
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[]{};
}
}
而現(xiàn)在我們可以用它來測(cè)試給定的值。
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()));
}
如果我們定義的任何字符不在給定的文件名中,這個(gè)Stream
謂詞返回真。此外,我們還實(shí)現(xiàn)了對(duì)null
值和不正確長(zhǎng)度的支持。
正則表達(dá)式模式匹配
我們也可以在給定的String
上直接使用正則表達(dá)式。讓我們來實(shí)現(xiàn)一個(gè)只接受字母數(shù)字和點(diǎn)字符的模式,其長(zhǎng)度不超過255。
public static final String REGEX_PATTERN = "^[A-za-z0-9.]{1,255}$";
public static boolean validateStringFilenameUsingRegex(String filename) {
if (filename == null) {
return false;
}
return filename.matches(REGEX_PATTERN);
}
現(xiàn)在,我們可以根據(jù)先前準(zhǔn)備的模式測(cè)試給定的值。我們還可以輕松地修改模式。在這個(gè)例子中,我們跳過了操作系統(tǒng)的檢查功能。
總結(jié)
在這篇文章中,我們集中討論了文件名及其限制。我們介紹了不同的算法,用Java檢測(cè)無效的文件名。
我們從java.io
包開始,它為我們解決了大部分的系統(tǒng)限制,但執(zhí)行了額外的I/O動(dòng)作,可能需要一些權(quán)限。然后我們檢查了NIO2 API,它是最快的解決方案,但有文件名長(zhǎng)度檢查的限制。
最后,我們實(shí)現(xiàn)了我們自己的方法,不使用任何I/O API,但需要自定義實(shí)現(xiàn)文件系統(tǒng)規(guī)則。
-
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
7057瀏覽量
124867 -
JAVA
+關(guān)注
關(guān)注
20文章
2984瀏覽量
106734 -
API
+關(guān)注
關(guān)注
2文章
1558瀏覽量
63439 -
文件
+關(guān)注
關(guān)注
1文章
577瀏覽量
25164
發(fā)布評(píng)論請(qǐng)先 登錄
數(shù)據(jù)結(jié)構(gòu)與算法分析(Java版)(pdf)
史上最全面Java面試匯總(面試題+答案)精選資料分享
Linux系統(tǒng)接口編程
用JAVA語言實(shí)現(xiàn)RSA公鑰密碼算法
中國(guó)農(nóng)歷算法java實(shí)現(xiàn)
基于java的負(fù)載均衡算法解析及源碼分享
安裝包是7.apk,要求獲取flag

數(shù)據(jù)結(jié)構(gòu)與算法分析——Java語言描述
Java智能卡EEPROM碎片整理算法

嵌入式 Linux 應(yīng)用程序開發(fā)概覽

評(píng)論