如果檔案被移動或刪除,開啟的檔案控制代碼會發生什麼?


概述

我們將瞭解當我們刪除、移動或替換具有開啟控制代碼的檔案時,作業系統的行為方式。

我們首先簡要介紹一下檔案和inode。之後,我們將檢視不同的場景,並瞭解每種情況下會發生哪種情況。

理解檔案和inode

儲存在 Linux 檔案系統上的檔案使用 inode 編號來跟蹤其內容。

我們通常透過列出其檔名(連結)然後列出其對應的 inode 編號(硬連結)來列出目錄的內容。

我們可以對檔案使用 stat 並檢視它引用哪個 inode -

$ touch inode_example
$ stat inode_example
   File: inode_example
   Size: 0              Blocks: 0          IO Block: 4096           regular empty file
Device: fd03h/64771d    Inode: 20448632    Links: 1

此檔案連結到 inode 204488632,並且 stat 還顯示有一個連結。讓我們新增一個新的硬連結檔案並再次在其上執行 stat。

$ ln inode_example hardlink_inode_example
$ stat inode_example
   File: inode_example
   Size: 0                 Blocks: 0             IO Block: 4096     regular empty file
Device: fd03h/64771d       Inode: 20448632       Links: 2

我們可以看到每個連結在其 URL 中都添加了一個增量值。我們現在也可以對 hardlink_inode_example 使用 stat -

$ stat hardlink_inode_example
   File: hardlink_inode_example
   Size: 0               Blocks: 0              IO Block: 4096       regular empty file
Device: fd03h/64771d     Inode: 20448632        Links: 2

與共享 inode 編號的硬連結不同,符號連結的 inode 編號與父目錄分開。

刪除檔案

每次我們建立新連線時,都會生成一個新程序。每個程序都有一個關聯的記憶體空間,資料儲存在其中。為了訪問資料,作業系統必須將地址轉換為記憶體空間內的物理位置。

讓我們建立一個名為 remove_opened_file 的 shell 檔案來測試我們的想法。

#!/bin/bash

FILE="/tmp/remove_example"
( 
   sleep 1
   echo "Before rm." >&4
   rm "$FILE"
   if [ ! -e "$FILE" ]; then
      echo "The file $FILE was removed."
   fi
   echo "After rm." >&4
) 4>"$FILE" &
( 
   sleep 2
   echo "This is the content in file handle 4:"
   cat <&4
) 4<"$FILE"

我們首先啟動兩個子 shell,然後我們使用重定向在每個子 shell 中建立和訪問 /tmp/remove_examples 作為檔案控制代碼 4。當子 shell 終止時,系統會關閉檔案控制代碼。

讓我們執行它並檢查它是否有效。

$ ./remove_opened_file.sh
The file /tmp/remove_example was removed.
This is the content in file handle 4:
Before rm.
After rm.

當我們刪除目錄時,我們實際上並沒有刪除其中的檔案;相反,我們只是刪除了檔名和 inode 之間的連結。因此,儘管檔案本身消失了,但它們仍然可以透過其 inode 訪問。

當系統刪除 inode 時,它會刪除其內容。

  • 沒有更多指向它的硬連結

  • 沒有開啟的檔案控制代碼

刪除檔案並不一定意味著可用磁碟儲存空間減少

移動檔案

系統有兩種方法可以將檔案從一個位置傳輸到另一個位置 -

  • 重新命名檔案

  • 將其內容複製到目標,然後刪除源

根據具體情況,程式會使用一種或另一種方法。例如,如果我們正在將檔案從一個位置複製到另一個位置,那麼程式可能會使用 Copy 命令。

檔案被重新命名

如果更改了原始檔名,則不會影響開啟的檔案。我們仍然可以寫入和讀取它們。由於 inode 相同,因此我們在移動後寫入的內容將寫入新位置。

讓我們編寫 move_open_file.sh 來測試移動開啟的檔案。

#!/bin/bash

FILE=/tmp/move_example
FILE_NEW=/tmp/move_example.new

( 
   echo "Before mv." >&4
   mv "$FILE" "$FILE_NEW";
   if [ ! -e "$FILE" -a -e "$FILE_NEW" ]; then
      echo "The file $FILE was moved to $FILE_NEW."
   fi
   echo "After mv." >&4
   echo "This is the content in $FILE_NEW:"
   cat "$FILE_NEW"
) 4>"$FILE"

在這裡,我們使用子 shell 和重定向,就像我們在上一個示例中所做的那樣。我們首先建立一個開啟的檔案控制代碼以寫入輸出檔案。然後,我們執行 mV 命令。

我們可以看出檔案是從相同位置複製的,因為它們具有相同的名稱。現在讓我們看看是否可以更改其名稱。

檔案 /tmp/move_example 已移動到 /tmp/move_example.new。

檔案被複制

當系統將源文件複製到目標位置時,不會保留源文件的原始內容。相反,副本僅包含源文件中包含的資訊。源文件關閉後,對源文件所做的任何更改都會丟失。

現在我們需要修改我們的 move_opened_files.sh 指令碼,以便目標位於單獨的檔案系統中。通常 /tmp 和 /home 位於不同的檔案系統中。結果如下 -

檔案 /tmp/move_example 已移動到 /home/baeldung/move_by_copy_example.new。

這是 /home/baeldung/move_by_copy_example.new 中的內容 -

Before mv.

替換檔案

當程式的新版本替換舊版本時,系統會刪除程式的舊版本。這意味著我們可以繼續使用舊版本的軟體,直到我們關閉應用程式的視窗。

我們可以編寫一個名為 replace_opened_file 的 shell 指令碼,該指令碼測試是否已將開啟的檔案替換為另一個檔案。

#!/bin/bash

FILE=/tmp/replace_example
FILE_OLD=/tmp/replace_example.old

echo "This is the old file." > $FILE_OLD

( 
   sleep 1
   echo "Before mv." >&4
   mv "$FILE_OLD" "$FILE"
   echo "After mv." >&4
) 4>"$FILE" &

( 
   sleep 2
   echo "This is the content in file handle 4:"
   cat <&4
   echo "This is the content in $FILE:"
   cat $FILE
) 4<"$FILE"

在此指令碼中,讓我們首先建立同一文件的舊版本。然後我們開啟一個新的 shell 並將同一文件的新版本寫入其中。最後,我們列印新寫入的文件的內容。

讓我們執行 replace_opened_file。

$ ./replace_opened_file.sh

這是檔案控制代碼 4 中的內容 -

Before mv.
After mv.

結論

我們研究了當我們刪除檔案、複製檔案或更改其位置時會發生什麼。

我們看到我們可以刪除或替換單個文件,並且我們仍然可以使用其開啟的文件控制代碼訪問它,即使我們已刪除或替換它。

一方面,我們看到如果我們將檔案移動到同一目錄中,則開啟的控制代碼將指向新檔案。但是,如果我們將其移動到另一個目錄,則開啟的檔案將指向舊檔案。

更新於: 2022-12-26

265 次瀏覽

開啟你的 職業生涯

透過完成課程獲得認證

開始
廣告