由於軟鏈接及android的外部卡mount方式存在,導致一個文件夾可能同時有兩個路徑,如: /mnt/sdcard1 /storage/ext_sdcard ,如果通過某種方式(如mount命令)得到了這兩個路徑,但是現在要給路徑去重,可以采用如下方法:
一、首先,要判斷目錄是否是同一個目錄,可能會用到判斷一個文件是否是同一個文件的方法,如果已經得到文件的路徑 filePath1 和 filePath2,則可以這樣來對比是否是同一個物理文件:
1、先檢查這兩個文件是否是符號鏈接,若是符號鏈接,通過采用File.getCanonicalPath()
的方法得到文件的正規路徑(Canonical
是規范的、正規的、正則的意思):
檢查文件是否是符號鏈接:
// 自己補上: 先檢查文件是否存在,不存在則直接返回 false
public static boolean isSymlink(File file) throws IOException { if (file == null) throw new NullPointerException("File must not be null"); File canon; if (file.getParent() == null) { canon = file; } else { File canonDir = file.getParentFile().getCanonicalFile(); canon = new File(canonDir, file.getName()); } return !canon.getCanonicalFile().equals(canon.getAbsoluteFile()); }
如果是符號鏈接,采用File.getCanonicalPath()
的方法得到文件的規范路徑:
// 自己加上:先檢查文件是否存在,不存在則直接返回 file.getAbsolutePath() 或者 a.getPath()
if (isSymlink(file)) {
return file.getCanonicalFile();
}
關於canonical pathname的解釋:
A canonical pathname is both absolute and unique. The precise definition of canonical form is system-dependent. This method first converts this pathname to absolute form if necessary, as if by invoking the getAbsolutePath() method, and then maps it to its unique form in a system-dependent way. This typically involves removing redundant names such as "." and ".." from the pathname, resolving symbolic links (on UNIX platforms), and converting drive letters to a standard case (on Microsoft Windows platforms).
2、得到文件的canonical path之后,對比文件的inode是否相等:
Runtime.getRuntime().exec("ls -i" + " " + file_canonical_path);
然后得到輸出后先trim,再split(" "),再判斷獲得的第一個元素是否全是數字,如果全是數字則是其inode。
二、判斷兩個目錄(A和B)是否是同一個目錄:
1、先通過查找某個文件夾目錄(如A)里的第一個文件,找到其相對路徑:
public void listFilesForFolder(final File folder) {
if (!folder.exists()) return;
for (final File fileEntry : folder.listFiles()) { if (fileEntry.isDirectory()) { listFilesForFolder(fileEntry); } else { System.out.println(fileEntry.getName()); } } }
上面的程序可以找到某文件夾里的所有文件,自己取某些文件即可。
得到該文件夾(A)的某些文件之后,通過獲得這些文件的 AbsolutePath 字符串,然后再從 這些 AbsolutePath 字符串里去掉 文件夾A的 AbsolutePath 字符串,就得到了這些文件的相對路徑。注意,建議別用網上找到的方法來獲取相對路徑(因為有些時候 toURI() 會改變文件的路徑,由於某些符號映射機制,如我的 android手機(華為榮耀7) 里的 /storage/sdcard1 就被映射成了 /storage/0123-4567,所有/storage/sdcard1目錄下的文件,調用 toURI()之后都被改變了根目錄為 /storage/0123-4567 ):
ring path = "/var/data/stuff/xyz.dat"; String base = "/var/data"; String relative = new File(base).toURI().relativize(new File(path).toURI()).getPath(); # 不要用這種方法獲取相對路徑
除了上面得到相對路徑的方法外,還有一種更好的方法得到第一個文件的相對路徑,建議用下面這種方法得到相對路徑:
public void listFilesForFolder(final File folder) { if (!folder.exists()) return; String relativePath = "";
String fileName = ""; for (final File fileEntry : folder.listFiles()) { if (fileEntry.isDirectory()) {
relativePath += fileEntry.getName() + "/"; listFilesForFolder(fileEntry); } else {
fileNmae = fileEntry.getName(); System.out.println(fileEntry.getName());
break; } } }
2、得到文件夾A里某些文件的相對路徑之后,在B文件夾里創建這些文件,即new File(B, fileRelativePath), 將這些文件與文件夾A的相應的文件進行對比,看看他們的inode是否相同。相同則表明A和B是同一個文件夾,如果不同,則不是同一個文件夾。方法如下:
假如從文件夾A得到里一個文件 dir/file1.txt,通過字串方式去掉前面A的路徑,自然語言描述如下:
File file1A = new File("A", "dir/file1.txt");
File file1B = new File("B", file1RelativePath);
if (!file1B.exists()) 則A和B不是同一個目錄;
if (file1B的inode等於file1A的inode)則是同一個目錄,否則不是。獲取inode的時候不用將符號鏈接變成Canonical Path,即不推薦將兩個文件都調用 getCanonicalFile(),因為如果A和B是同一個文件夾,則它里面的文件(哪怕是符號鏈接文件)也應該是同一個文件。