FlossDoc: 請協力 GPLv3 的中文翻譯工作。

存取 FAT 檔案系統

FlossDoc,自由中文開源知識庫

Jump to: navigation, search

GNU/Linux 可以輕易存取 FAT 檔案系統。現代 GNU/Linux 的桌面環境如 GNOMEKDE 都使用 udevD-Bus。當您插入任何標準抽取式儲存裝置 (包括 USB 硬碟、快閃記憶卡、儲存器、MP3 播放機和數碼相機等),系統一般會自動識別,掛載和開啟檔案管理員,讓您存取其內容。您亦可以在桌面 (desktop) 或『電腦』(Computer, computer:///) 之類的資料夾找對應儲存裝置的小圖示。然而在欠缺 X Window 的文字模式、伺服器環境或舊 X Window 系統中,就往往需要手動使用命令 mount

本文主要講解如何存取直接連接電腦的 FAT 檔案系統儲存裝置。要存取網絡上的檔案,請參閱《存取網絡上 Windows 系統上的檔案》

目录

掛載 FAT 檔案系統

Unix/Linux 要存取儲存裝置 (storage device)/檔案系統 (filesystem) 中的檔案或任何的內容,需要先掛載 (mount) 檔案系統至一個目錄後,才可以在該目錄中存取檔案系統中的檔案。而該目錄亦叫作掛載點 (mount point)。掛載檔案系統的工作一般是使用命令 mount 進行。

簡單而言,掛載儲存裝置中的檔案系統的命令「mount -t 檔案系統類型 儲存裝置 掛載點」,例如:

mount -t vfat /dev/sda1 /media/disk

識別儲存裝置

初學者遇到的第一個問題一般都是究竟要掛載的儲存裝置的裝置檔案名稱是什麼?如果您已知道了,請跳過本節到下一節《掛載 (mount)》

在 Unix/Linux 世界中,每一個連接了的裝置都在目錄 /dev 中有一個對應的裝置檔案,例如 /dev/sda 代表了第一個 SATA/SCSI 硬碟。近年版本的 GNU/Linux 大都使用 libATA,包括 PATA/SATA/SCSI/USB/IEEE1394 等大部份儲存裝置一律採用統一的命名法 — /dev/sda 代表第一顆儲存裝置,一般亦是啟動系統的儲存裝置,第二個插入的儲存裝置會叫作 /dev/sdb,第三個則叫 /dev/sdc,以此類推。

留意在舊或沒有使用 libATA 的 GNU/Linux 系統中,PATA 硬碟用 /dev/hda 或 /dev/hdb 等表示。/dev/hda 代表連接 PATA 第一排線 master 的硬碟,/dev/hdb 代表第一排線 slave,/dev/hdc 為第二排線 master,/dev/hdd 是第二排線 slave。第一排線只連接一顆硬碟時,就會沒有 /dev/hdb 但有 /dev/hdc 的情況。此外,這些 GNU/Linux 系統中的 PCMCIA/CF 的儲存裝置都會當成 PATA 裝置處理,裝置檔案很多時會變成 /dev/hde 或 /dev/hdf 等。

這可能令您很混亂,但如果有關儲存裝置是剛插入系統中,您可以查看 Linux 核心發出的訊息來獲知其裝置檔案的正確名稱。當有裝置被插入到電腦時,Linux 核心應該會感應到。您可以打「dmesg」查看核心的訊息,看看核心能否成功辯認到插入的裝置,並找出裝置分配到那個裝置檔案:

usb 2-1: new full speed USB device using uhci_hcd and address 3
usb 2-1: configuration #1 chosen from 1 choice
scsi1 : SCSI emulation for USB Mass Storage devices
  Vendor: KINGMAX   Model: USB2.0 Flashdisk  Rev: 2.00
  Type:   Direct-Access                      ANSI SCSI revision: 02
scsi 1:0:0:0: Attached scsi generic sg1 type 0
SCSI device sdb: 4030463 512-byte hdwr sectors (2064 MB)
sda: Write Protect is off
SCSI device sdb: 4030463 512-byte hdwr sectors (2064 MB)
sdc: Write Protect is off
 sdb: sdb1

以上內容顯示有一張有 2GB 的 USB 2.0 快閃記憶卡插入電腦中,Linux 把它分配到裝置檔案 /dev/sdb,並偵出其有一個分割區 /dev/sdb1。

如果您的系統有 udev,您也可以看看目錄 /dev/disk/by-id 的內容。udev 會在目錄 /dev/disk/by-id 建立一些以裝置名稱為名的連結 (symbolic link) 指去實質的裝置檔案。以下是「ls -l /dev/disk/by-id」的結果:

總計 0
lrwxrwxrwx 1 root root  9 2007-11-20 09:46 ata-FUJITSU_MHT2030AT_NN6CT3B12W1D -> ../../sda
lrwxrwxrwx 1 root root 10 2007-11-20 09:46 ata-FUJITSU_MHT2030AT_NN6CT3B12W1D-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 2007-11-20 09:46 ata-FUJITSU_MHT2030AT_NN6CT3B12W1D-part2 -> ../../sda2
lrwxrwxrwx 1 root root 10 2007-11-20 09:46 ata-FUJITSU_MHT2030AT_NN6CT3B12W1D-part5 -> ../../sda5
lrwxrwxrwx 1 root root 10 2007-11-20 09:46 ata-FUJITSU_MHT2030AT_NN6CT3B12W1D-part6 -> ../../sda6
lrwxrwxrwx 1 root root  9 2007-11-20 22:38 usb-KINGMAX_USB2.0_Flashdisk_59000000000056 -> ../../sdb
lrwxrwxrwx 1 root root 10 2007-11-20 22:39 usb-KINGMAX_USB2.0_Flashdisk_59000000000056-part1 -> ../../sdb1
lrwxrwxrwx 1 root root 10 2007-11-20 22:19 usb-MATSHITA_DVD-RAM_UJ-850S_DEF13BA9C057 -> ../../scd0

以上表示 ATA Fujitsu 硬碟指向 /dev/hda,Kingmax USB 快閃記憶卡指向 /dev/sda。

如果在 dmesg 找不到和裝置相關的訊息,Linux 可能未能成功偵測您的儲存裝置。您可以試一試用 modprobe 載入上面提到的核心模組,再打「dmesg」看看有什麼進展:

modprobe usb_storage
dmesg

如果仍然沒有進展,您需要檢查您的 Linux 核心是否為編譯相關模組或者更新您的 Linux 核心。

掛載 (mount)

要掛載儲存裝置中的 FAT 檔案系統,可以使用命令「mount -t vfat 儲存裝置 掛載點[1],例如:

mount -t vfat /dev/sdb1 /mnt

掛載前,掛載點的目錄必需已經存在。完成後,您可以在掛載點的目錄 (如上例的 /mnt) 存取儲存裝置中的檔案。您亦可以使用命令 dfmount 確定檔案系統已成功被掛載:

$ mount
/dev/sda6 on / type ext3 (rw,noatime,errors=remount-ro)
...
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
/dev/sdb1 on /mnt type vfat (rw)

或者:

$ df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda6             10317828   5018496   4775216  52% /
...
tmpfs                  1031792       216   1031576   1% /dev/shm
/dev/sdb1             8315592     912476   7403116  11% /mnt

看見顯示以掛載儲存裝置為首的一行就表示掛載成功了。

除了 vfat 外,您亦可以使用 msdos 作為檔案系統類型掛載 FAT 檔案系統,而舊版 GNU/Linux 有一個檔案系統類型 - umsdos 亦可以用作掛載 FAT 檔案系統。然而 msdos 掛載的檔案系統會使用傳統 MSDOS 的 8.3 短檔案名稱。檔案系統類型 umsdos 則可以在 FAT 檔案系統使用 Unix/Linux 的檔案系統功能,包括長檔案名稱、所屬使用者和存取權限 (umsdos 把這些額外資料存放在每一個目錄中的 --linux-.--- 檔案中),主要在早期用作把整個 GNU/Linux 檔案系統放在 FAT 檔案系統上,免除重新分割硬碟的麻煩。然而 umsdos 的長檔案名稱和 Windows 系統上 FAT 的長檔案名稱並不兼容,使用 umsdos 的 GNU/Linux 又比使用 ext2 的系統慢,所以很少被採用。至 Linux 2.6 已不再支援 umsdos。

掛載如快閃記憶卡或 USB/IEEE1394 硬碟等抽取式儲存裝置時,您未必知道裝置中檔案系統的類型。如果您略去 -t 檔案系統類型 選項或使用 -t auto,令 mount 自動偵測檔案系統的類型:

mount /dev/sdb1 /mnt

這顯然對掛載抽取式儲存裝置有很大幫助。現代 GNU/Linux 中的 mount 會透 一般而言,mount 的偵測能力都很準確,但萬一 mount 使用錯誤的檔案系統類型掛載,有機會破壞當中的資料。

掛載成唯讀 (read-only, ro) 模式

除儲存裝置開啟了 write-protect 或儲存裝置為唯讀媒體,mount 命令掛載時預設使用讀寫 read-write, rw) 模式,讓使用者閱讀檔案系統的內容之餘,亦可以增加、刪除檔案或編輯檔案。然而,如果您想保護檔案系統內容,不想被人更改,您亦可以把整個檔案系統掛載成唯讀 (read-only) 模式,那無論檔案系統中的檔案權限為何,所有使用者包括系統管理員 root 都不能改變其內容。要掛載檔案系統成唯讀模式,只需要在 mount 命令加上 -r-o ro 選項,例如:

mount -t vfat -r /dev/sda1 /media/windows

或者:

mount -t vfat -o ro /dev/sdc1 /media/usbdisk

控制 FAT 檔案系統在 GNU/Linux 上的存取權限

  • uid=uid - FAT 檔案系統中的檔案沒有所屬使用者,這選項可以所有檔案指定為 uid 使用者。預設為進行 mount 的使用者。
  • gid=gid - FAT 檔案系統中的檔案沒有所屬使用者,這選項可以所有檔案指定為 uid 使用者。預設為進行 mount 的使用者。
  • umask=umask - 設定 FAT 檔案系統中檔案和目錄的存取權限 (permission)。預設為進行 mount 時的 umask 值。
  • dmask=dmask - 設定 FAT 檔案系統中目錄的存取權限 (permission)。預設為進行 mount 時的 umask 值。
  • fmask=fmask - 設定 FAT 檔案系統中一般檔案的存取權限 (permission)。預設為進行 mount 時的 umask 值。

使用長檔案名稱或短檔案名稱 (8.3 檔案名稱)

掛載 FAT 檔案系統時使用 msdos 作為檔案系統類型會令掛載檔案系統中的檔案使用傳統的 8.3 (八個字元的檔案名稱和三個字元的伸廷檔名) 格式短檔案名稱:

mount -t msdos /dev/sde3 /media/usbdisk

使用檔案系統類型 vfat 則使用長檔案名稱 (最長 255 個 Unicode 字元)。兩者不能同時在同一媒體使用。

改變 FAT 檔案的屬性

現時的 GNU/Linux 可以使用 chmod -w 檔案名稱 開啟唯讀屬性 (Read-only attribute) 或 chmod +w 檔案名稱 關閉,但其他包括隱藏 (hidden)、系統 (system) 和封存 (archive) 等屬性則要使用 fatattr 可以更改。詳情請參閱《改變 FAT 檔案的屬性》

卸載 (unmount)

要卸載檔案系統,可以使用命令「umount 儲存裝置」或「umount 掛載點[2](“u” 後確實沒有 “n”,並白字),例如:

umount /dev/sdc1

如果輸入 umount 命令後停頓下來,一般表示系統正在把仍在緩衝區 (buffer) 中的資料寫入儲存裝置。此時切忌移除該儲存裝置,否則將有機會損壞檔案系統或掉失部份資料。待提示符 #$' 再出現時才表示卸載完畢:

$ umount /dev/sdc1
$

如果中間沒有什麼錯誤訊息出現,一般都表示卸載成功。您可以使用 dfmount 等命令列出已掛載的檔案系統以確定有關檔案系統已成功卸載。

退出媒體 (eject media)

有些媒體 (media) 包括軟碟、JAZ 碟、ZIP 碟和 ipod 等可能需要由軟件控制才可能從電腦中退出媒體,這時就需要使用 eject 了。eject[3] 的使用方法是「eject 名稱」,例如:

eject /media/disk

參數 “名稱” 可以是裝置檔案 (/dev/fd0 或 /dev/sdb1 等) 或裝置的掛置點 (/media/disk 或 /mnt 等)。亦可以是以上兩者略上 /dev/、/media/ 或 /mnt/ 等父目錄名稱。執行 eject 時, 如果發現 “名稱” 的第個字元是 “/” 或 “.”,會直接退出所指裝置。否則會在前加上 /dev/、/media/、/mnt/、/dev/cdroms、/dev/rdsk、/dev/dsk 或 ./,直接找到所指裝置。所以您可以直接使用 sdb1 和 disk 等退出裝置:

 eject sdb1 

解決卸載失敗問題 “device is busy”

大部人在卸載或退出儲存裝置時都曾遇見以下訊息而被拒絶卸載或退出:

umount: /media/sdc1: device is busy

這表示有些程序仍在開啟儲存裝置中某些檔案作讀或寫,如果這時移除裝置,有機會會損壞檔案系統、掉失資料和損害該程序,所以系統會拒絶卸載或退出。此時,您需找出仍在使用儲存裝置的程序並要求它們關閉相關檔案 (一般的方法是直接結束相關程序),才可以正常卸載或退出媒體。其中一個方法就是可以使用「fuser -m 掛載點[4]列出正在使用裝置掛載點目錄以下檔案的程序:

$ fuser -m /media/sdc1
/media/sdc1          6015c  6132

表示程序識別碼 (PID) 為 6015 和 6132 的程序是在使用 /media/sdc1 或以下的檔案。PID 後的英文字母表示檔案/目錄如何被使用:

  • c - 當前目錄
  • e - 程序被執行的目錄
  • f - 開啟檔案。fuser 的預設顯示模式會省去 f
  • F - 開啟檔案作寫入。fuser 的預設顯示模式同樣會省去 F
  • r - 根目錄
  • m - 使用 mmap 開啟了檔案或分享程式庫 (shared library)

在 fuser 命令加上選項 -v 可以顯示較詳細的資訊:

$ fuser -vm /media/sdc1
                     USER        PID ACCESS COMMAND
/media/sdc1:     johndoe    6015 ..c.. bash
                     johndoe    6132 f.... rhythmbox

亦使用命令「ps auxw | grep PID」獲知個別程序的詳細資訊:

$ ps auxw | grep 6132
johndoe 6132 0.4 3.0   220017 57104 ?  S+ 18:27 0:00 rhythmbox

以上畫面顯示音樂播放程式 Rhythmbox 使用了儲存裝置,您只需要關掉 Rhythmbox 或播放清單,就可以卸載或退出儲存裝置。

除 fuser 外,亦使用命令 「lsof 掛載點[5]列出正在使用裝置掛載點目錄以下檔案的程序:

$ lsof /media/sdc1
COMMAND  PID    USER   FD   TYPE DEVICE SIZE NODE NAME
bash    7531 johndoe  cwd    DIR   11,0 4096 1856 /media/sdc1
lsof    7698 johndoe  cwd    DIR   11,0 4096 1856 /media/sdc1
lsof    7699 johndoe  cwd    DIR   11,0 4096 1858 /media/sdc1

以上畫面表示有一個 bash 和兩個 lsof 程序正在使用 /media/sdc1,您需要令它們全部關閉 /media/sdc1 才可以退出該裝置。當然,直接結束相關程序是最簡單或一般情況下唯一的方法。

此時您可能會發覺有些很諷刺的事情發生。超過一半的情況,您所使用的命令模式或終端機就是正在使用裝置和阻止您退出卸載的程式,如上面畫面就是這個程式,bash 程序就是正在使用的命令模式,而兩個 lsof 程序就是剛為查詢而輸入的命令,它們合部都使用 /media/sdc1 作為當前工作目錄 (current working directory),令系統拒絕卸載。解決方法就是改變工作目錄至 /media/sdc1 及以下以外的目錄就可以了:

$ cd
$ pwd
/home/johndoe
$ eject sdc1
$

很多情況下,我們需要終止有關程序才可以令它不再使用有關裝置而讓我們卸載或退出裝置。這當然不是一個好方法,有關程序如未儲存檔案,可能會遺失一些資料。但這卻是最簡單快捷的方法。建議初學者在無計可施時才好出此懶人的下策:

$ umount /media/sdb1
umount: /media/sdb1: device is busy
umount: /media/sdb1: device is busy
$ lsof /media/sdb1
COMMAND   PID    USER   FD   TYPE DEVICE SIZE NODE NAME
bash    67429 johndoe  cwd    DIR   11,0 4096 4257 /media/sdb1/documents
$ kill 67429
$ lsof /media/sdb1
COMMAND   PID    USER   FD   TYPE DEVICE SIZE NODE NAME
bash    67429 johndoe  cwd    DIR   11,0 4096 4257 /media/sdb1/documents
$ kill -9 67429
$ lsof /media/sdb1
$ umount /media/sdb1
$ umount /media/sdb1

參考資料

  1. GNU/Linux Manpage: mount(8) - mount a filesystemLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] - GNU/Linux 中的 mount(8) 說明文件
  2. GNU/Linux Manpage: umount(8) - unmount file systemsLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] - GNU/Linux 中的 umount(8) 說明文件
  3. GNU/Linux Manpage: eject(1) - eject removable mediaLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] - GNU/Linux 中的 eject(1) 說明文件
  4. GNU/Linux Manpage: fuser(1) - identify processes using files or socketsLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] - GNU/Linux 中的 fuser(1) 說明文件
  5. GNU/Linux Manpage: lsof(8) - list open filesLinux.pngUbuntu.pngDebian.png[SuSE][OpenSuSE] - GNU/Linux 中的 lsof(8) 說明文件

請參看

外部連結

Personal tools