[英]Is there a cross-platform Java method to remove filename special chars?
我正在制作一個跨平台的應用程序,它根據在線檢索的數據重命名文件。 我想清理我從當前平台的 Web API 中獲取的字符串。
我知道不同的平台有不同的文件名要求,所以我想知道是否有跨平台的方式來做到這一點?
編輯:在 Windows 平台上,您不能有問號“?” 在文件名中,而在 Linux 中,您可以。 文件名可能包含這些字符,我希望支持這些字符的平台保留它們,否則,將它們去掉。
此外,我更喜歡不需要第三方庫的標准 Java 解決方案。
正如其他地方所建議的,這通常不是您想要做的。 通常最好使用諸如 File.createTempFile() 之類的安全方法來創建臨時文件。
您不應該使用白名單來執行此操作,而應僅保留“好”字符。 如果文件僅由中文字符組成,那么您將刪除所有內容。 出於這個原因,我們不能使用白名單,我們必須使用黑名單。
Linux 幾乎允許任何可能是真正痛苦的事情。 我只是將 Linux 限制在與您限制 Windows 相同的列表中,這樣您將來就可以省去麻煩。
在 Windows 上使用這個 C# 片段我生成了一個在 Windows 上無效的字符列表。 此列表中的字符比您想象的要多得多 (41),因此我不建議您嘗試創建自己的列表。
foreach (char c in new string(Path.GetInvalidFileNameChars()))
{
Console.Write((int)c);
Console.Write(",");
}
這是一個“清理”文件名的簡單 Java 類。
public class FileNameCleaner {
final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};
static {
Arrays.sort(illegalChars);
}
public static String cleanFileName(String badFileName) {
StringBuilder cleanName = new StringBuilder();
for (int i = 0; i < badFileName.length(); i++) {
int c = (int)badFileName.charAt(i);
if (Arrays.binarySearch(illegalChars, c) < 0) {
cleanName.append((char)c);
}
}
return cleanName.toString();
}
}
編輯:正如斯蒂芬建議的那樣,您可能還應該驗證這些文件訪問是否僅發生在您允許的目錄中。
以下答案包含用於在 Java 中建立自定義安全上下文然后在該“沙箱”中執行代碼的示例代碼。
或者只是這樣做:
String filename = "A20/B22b#öA\\BC#Ä$%ld_ma.la.xps";
String sane = filename.replaceAll("[^a-zA-Z0-9\\._]+", "_");
結果: A20_B22b_A_BC_ld_ma.la.xps
解釋:
[a-zA-Z0-9\\\\._]
匹配 az 小寫或大寫字母、數字、點和下划線
[^a-zA-Z0-9\\\\._]
是相反的。 即所有與第一個表達式不匹配的字符
[^a-zA-Z0-9\\\\._]+
是與第一個表達式不匹配的字符序列
因此,每個不包含 az、0-9 或 . _ 將被替換。
這是基於Sarel Botha接受的答案,只要您沒有遇到Basic Multilingual Plane之外的任何字符,它就可以正常工作。 如果您需要完整的 Unicode 支持(誰不需要?),請改用此代碼,這是 Unicode 安全的:
public class FileNameCleaner {
final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};
static {
Arrays.sort(illegalChars);
}
public static String cleanFileName(String badFileName) {
StringBuilder cleanName = new StringBuilder();
int len = badFileName.codePointCount(0, badFileName.length());
for (int i=0; i<len; i++) {
int c = badFileName.codePointAt(i);
if (Arrays.binarySearch(illegalChars, c) < 0) {
cleanName.appendCodePoint(c);
}
}
return cleanName.toString();
}
}
這里的主要變化:
length
而不僅僅是length
charAt
append
char
s 轉換為int
s。 事實上,你永遠不應該處理char
因為它們基本上被 BMP 之外的任何東西破壞了。這是我使用的代碼:
public static String sanitizeName( String name ) {
if( null == name ) {
return "";
}
if( SystemUtils.IS_OS_LINUX ) {
return name.replaceAll( "[\u0000/]+", "" ).trim();
}
return name.replaceAll( "[\u0000-\u001f<>:\"/\\\\|?*\u007f]+", "" ).trim();
}
SystemUtils
來自Apache commons-lang3
有一個非常好的內置 Java 解決方案 - Character.isXxx() 。
嘗試Character.isJavaIdentifierPart(c)
:
String name = "name.é+!@#$%^&*(){}][/=?+-_\\|;:`~!'\",<>";
StringBuilder filename = new StringBuilder();
for (char c : name.toCharArray()) {
if (c=='.' || Character.isJavaIdentifierPart(c)) {
filename.append(c);
}
}
結果是“name.é$_”。
從您的問題中不清楚,但是由於您計划接受來自網絡表單 (?) 的路徑名,您可能應該阻止重命名某些內容的嘗試; 例如“C:\\Program Files”。 這意味着您需要規范化路徑名以消除“.”。 和“..”,然后再進行訪問檢查。
鑒於此,我不會嘗試刪除非法字符。 相反,我會使用“new File(str).getCanonicalFile()”來生成規范路徑,接下來檢查它們是否滿足您的沙箱限制,最后使用“File.exists()”、“File.isFile()”等來檢查源和目標是否是 kosher 並且不是同一個文件系統對象。 我會通過嘗試執行操作並捕獲異常來處理非法字符。
Paths.get(...)
拋出一個包含非法字符位置的詳細異常。
public static String removeInvalidChars(final String fileName)
{
try
{
Paths.get(fileName);
return fileName;
}
catch (final InvalidPathException e)
{
if (e.getInput() != null && e.getInput().length() > 0 && e.getIndex() >= 0)
{
final StringBuilder stringBuilder = new StringBuilder(e.getInput());
stringBuilder.deleteCharAt(e.getIndex());
return removeInvalidChars(stringBuilder.toString());
}
throw e;
}
}
如果您想使用的不僅僅是 [A-Za-z0-9],請檢查MS Naming Conventions ,並且不要忘記過濾掉“...整數表示在 1 到 31 范圍內的字符,... ”,就像 Aaron Digulla 的例子一樣。 例如來自 David Carboni 的代碼對於這些字符是不夠的。
包含保留字符列表的摘錄:
使用當前代碼頁中的任何字符作為名稱,包括 Unicode 字符和擴展字符集 (128–255) 中的字符,但以下字符除外:
以下保留字符:
<
(小於)>
(大於):
冒號)"
(雙引號)/
(正斜杠)\\
(反斜杠)|
(垂直條或管)?
(問號)*
(星號)- 整數值零,有時稱為 ASCII NUL 字符。
- 整數表示在 1 到 31 范圍內的字符,但允許這些字符的備用數據流除外。 有關文件流的更多信息,請參閱文件流。
- 目標文件系統不允許的任何其他字符。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.