ZetCode

Python os.link 函数

上次修改时间:2025 年 4 月 11 日

本综合指南探讨 Python 的 os.link 函数,该函数用于在文件之间创建硬链接。我们将介绍链接创建、文件系统行为以及硬链接的实际使用示例。

基本定义

os.link 函数创建一个硬链接,指向与源文件相同的 inode。硬链接共享磁盘上的相同数据块。

关键参数:src(源文件路径),dst(目标链接路径)。要求两个文件都在同一文件系统上。失败时引发 OSError。

创建基本的硬链接

os.link 最简单的用法是为现有文件创建一个新的硬链接。这两个文件都将引用磁盘上的相同物理数据。

basic_link.py
import os

# Create a sample file
with open("original.txt", "w") as f:
    f.write("This is the original file content")

# Create a hard link
os.link("original.txt", "link.txt")

# Verify both files exist and have same content
print(f"Original exists: {os.path.exists('original.txt')}")
print(f"Link exists: {os.path.exists('link.txt')}")

with open("link.txt") as f:
    print(f"Link content: {f.read()}")

此示例创建一个文件,然后为其创建一个硬链接。由于它们指向相同的数据块,因此这两个文件将显示相同的内容。

通过任一文件名进行的更改都将在两个文件中可见,因为它们引用相同的底层文件。

检查链接计数

我们可以使用 os.stat 检查链接计数 (nlink),该计数显示有多少硬链接指向一个文件。每次创建新链接时,此计数都会增加。

link_count.py
import os

# Create initial file
with open("data.txt", "w") as f:
    f.write("Sample data")

# Check initial link count
stat = os.stat("data.txt")
print(f"Initial link count: {stat.st_nlink}")

# Create first hard link
os.link("data.txt", "backup1.txt")
stat = os.stat("data.txt")
print(f"After first link: {stat.st_nlink}")

# Create second hard link
os.link("data.txt", "backup2.txt")
stat = os.stat("data.txt")
print(f"After second link: {stat.st_nlink}")

这显示了链接计数如何随着每个新的硬链接而增加。删除链接时计数会减少,当计数达到 0 时,文件将被删除。

所有硬链接都是相等的 - 在文件系统级别没有“原始”与“链接”的区别。

跨目录链接

只要它们位于同一文件系统上,就可以在不同的目录中创建硬链接。此示例演示了跨目录链接。

cross_directory.py
import os

# Create directory structure
os.makedirs("docs", exist_ok=True)
os.makedirs("backups", exist_ok=True)

# Create source file
with open("docs/report.txt", "w") as f:
    f.write("Quarterly financial report")

# Create cross-directory link
os.link("docs/report.txt", "backups/report_backup.txt")

# Verify link
print(f"Original size: {os.path.getsize('docs/report.txt')}")
print(f"Link size: {os.path.getsize('backups/report_backup.txt')}")

# Modify through link
with open("backups/report_backup.txt", "a") as f:
    f.write("\nUpdated version")

# Check original content
with open("docs/report.txt") as f:
    print(f.read())

这在一个目录中创建一个文件,并从另一个目录链接到它。通过任一路径进行的更改都会反映在这两个路径中,因为它们共享存储。

目录必须位于同一文件系统分区上,硬链接才能工作。

错误处理

os.link 可能会引发各种异常。此示例展示了针对常见情况(如缺少源或存在目标)的正确错误处理。

error_handling.py
import os
import errno

def create_link(src, dst):
    try:
        os.link(src, dst)
        print(f"Created link {dst} -> {src}")
    except FileNotFoundError:
        print(f"Error: Source file {src} does not exist")
    except FileExistsError:
        print(f"Error: Destination {dst} already exists")
    except PermissionError:
        print(f"Error: Permission denied for {dst}")
    except OSError as e:
        if e.errno == errno.EXDEV:
            print("Error: Cross-device linking not allowed")
        else:
            print(f"Error: {e.strerror}")

# Test cases
create_link("nonexistent.txt", "link.txt")  # Missing source
create_link("original.txt", "original.txt")  # Same file
create_link("/etc/passwd", "passwd.link")    # Permission denied (usually)
create_link("file1.txt", "/mnt/otherfs/link.txt")  # Cross-device

这演示了处理创建硬链接时可能发生的各种错误情况。每种情况都提供有关失败的特定反馈。

当文件系统操作失败时,正确的错误处理使程序更加健壮和用户友好。

链接与复制

此示例将硬链接与文件副本进行对比,显示它们在存储使用和修改传播方面的不同行为。

link_vs_copy.py
import os
import shutil

# Create original file
with open("data.txt", "w") as f:
    f.write("Original content")

# Create hard link
os.link("data.txt", "hardlink.txt")

# Create copy
shutil.copy2("data.txt", "copy.txt")

# Check initial sizes
print(f"Original size: {os.path.getsize('data.txt')}")
print(f"Hardlink size: {os.path.getsize('hardlink.txt')}")
print(f"Copy size: {os.path.getsize('copy.txt')}")

# Modify original
with open("data.txt", "a") as f:
    f.write("\nAdded line")

# Check updated content
print("\nAfter modification:")
with open("hardlink.txt") as f:
    print(f"Hardlink: {f.read()}")

with open("copy.txt") as f:
    print(f"Copy: {f.read()}")

硬链接会立即反映对原始文件的更改,而副本保持不变。硬链接共享存储,而副本使用额外的空间。

硬链接对于创建对同一数据的多个引用而无需复制存储非常有效。

检查硬链接

我们可以通过使用 os.stat 比较 inode 编号和设备 ID 来识别硬链接。此示例查找给定文件的所有硬链接。

find_links.py
import os

def find_hard_links(target_path):
    target_stat = os.stat(target_path)
    links = []
    
    for root, dirs, files in os.walk("/"):
        for file in files:
            file_path = os.path.join(root, file)
            try:
                file_stat = os.stat(file_path)
                if (file_stat.st_ino == target_stat.st_ino and 
                    file_stat.st_dev == target_stat.st_dev):
                    links.append(file_path)
            except:
                continue
                
    return links

# Create test file and links
with open("master.txt", "w") as f:
    f.write("Master file")

os.link("master.txt", "link1.txt")
os.link("master.txt", "link2.txt")

# Find all links
print("Hard links found:")
for link in find_hard_links("master.txt"):
    print(link)

这会扫描文件系统(从根目录开始)以查找与目标文件共享相同 inode 和设备的的所有文件。这标识了文件的所有硬链接。

请注意,这是大型文件系统上的昂贵操作,可能需要 root 权限才能访问所有目录。

安全注意事项

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程