通過快捷方式.lnk獲得文件真實路徑
前提
最近開發資源管理,需要預先上傳大量資源,負責整理資源的同學因為空間不足,直接用快捷鍵方式整理視頻資源OTZ,所以只能想辦法通過.lnk文件獲得文件的真實地址。
以下所有內容都來自網絡,博主僅做了參考與總結。
.lnk文件格式解析
此處對lnk文件組成做一個大概介紹主旨是幫助了解如何從link文件中提取需要的信息
一個lnk文件包括一下幾個模塊:
模塊 備注
注意:
不是所有的模塊都必須包含在內,但如果存在就要按上述的順序排列。
以下我們詳細了解需要用到的兩個模塊:
1. 文件頭(lnk file header)
偏移 長度 類型 備注
0x14處16進制數的含義:

0x18處16進制數的含義:

2. 文件位置信息段(File location info)

0x08偏移flags 具體含義:
如果目標文件是本地文件,那么文件名稱 = 本地路徑信息+剩余偏移路徑
如果目標文件是網絡文件,那么文件名稱 = 網絡卷中共享名稱+剩余偏移路徑
所以,File location info節之后的數據是,本地卷信息表,及網絡卷信息表。
1. 本地卷信息表結構

2. 網絡卷信息表結構

注意:
八個比特(Bit)稱為一個字節(Byte),兩個字節稱為一個字(Word),兩個字稱為一個雙字(Dword),兩個雙字稱為一個四字(Qword)。
代碼
private void parseLink(File f) throws FileNotFoundException, IOException {
FileInputStream fin = new FileInputStream(f);
byte[] link = new byte[(int)f.length()];
//讀取文件中的內容到link[]數組
fin.read(link);
fin.close();
// 判斷當前文件是否為快捷方式
if(!isLnkFile(link)){
return;
}
// 獲得flags信息
byte flags = link[0x14];
int shell_len = 0;
// 0000 0000 xxxx xxxx & 0000 0000 0000 0001(判斷是否包含shell item id list段)
if((flags & 0x1) > 0) {
// 如果存在,則獲取shell item id list段的總長度,加2是為了將link[0x4c]本身的長度計算在內
shell_len = bytes2short(link,0x4c) + 2;
}
// 獲得文件位置信息段的開始位置=shell item id list段的開始位置+shell item id list段的總長度
int file_start = 0x4c + shell_len;
// 獲取本地路徑信息的偏移
int local_sys_off = link[file_start + 0x10] + file_start;
String real_file = getNullDelimitedString(link, local_sys_off);
System.out.println(real_file);
}
private boolean isLnkFile(byte[] link) {
if (link[0x00]== 0x4c) {// 76,L,0x4c代表lnk文件格式
return true;
}
return false;
}
/**
* 將兩個字節轉換為short<br>
* 注意,因為僅限英特爾操作系統,所以這是小端字節<br>
*/
private int bytes2short(byte[] bytes, int off) {
return bytes[off] | (bytes[off + 1] << 8);
}
/**
* 獲得從偏移位置off到以‘0’為結尾分割字符串
* @param bytes 源數組
* @param off 偏移位置
* @return 字符串
*/
private String getNullDelimitedString(byte[] bytes, int off) {
int len = 0;
// 計算字符串占用數組的真實長度
while (true) {
if (bytes[off + len] == 0) {
break;
}
len++;
}
byte[] results = new byte[len];
for (int i = off, j = 0; i < off + len; i++, j++) {
results[j] = bytes[i];
}
try {
// 因為我是中文系統,所以設置了字符集GBK,否則中文路徑會出現亂碼
return new String(bytes, off, len, "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
import sys
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shortcut = shell.CreateShortCut("t:\\test.lnk")
print(shortcut.Targetpath)
