CodeGym /Các khóa học /C# SELF /Di chuyển tệp và thư mục

Di chuyển tệp và thư mục

C# SELF
Mức độ , Bài học
Có sẵn

1. Giới thiệu

Có rất nhiều scenario cần thao tác di chuyển: chuyển các file "đã tải" từ thư mục tạm sang thư mục Documents, sắp xếp hàng loạt ảnh, đổi tên theo mẫu, xử lý mail và logs. Hệ thống file thích sự ngăn nắp — hoặc ít nhất là giả vờ như vậy! Và một dev tốt phải biết cách tạo ra thứ tự đó.

Với lại những bài này thường xuất hiện trong phỏng vấn: "Viết một utility đổi tên tất cả file bằng cách thêm số phiên bản", hoặc "Tạo lệnh di chuyển các tài liệu cũ vào archive". Cùng tìm hiểu cách làm trên C#.

Tổng quan về khả năng

Trong .NET có hai cách chính để di chuyển và đổi tên — dùng các phương thức static (File.Move, Directory.Move) hoặc các phương thức instance (FileInfo.MoveTo, DirectoryInfo.MoveTo). Tất cả mấy phương thức này về cơ bản làm gần như giống nhau — khác chủ yếu ở cú pháp.

.NET "nhìn" việc di chuyển và đổi tên như thế nào?

Chú ý! Đổi tên và di chuyển về bản chất là cùng một thao tác: file hoặc thư mục được định danh bằng đường dẫn. Nếu đường dẫn thay đổi — coi như đối tượng "đã di chuyển" hoặc "đã đổi tên". Nếu bạn chỉ thay tên mà giữ nguyên thư mục — đó là đổi tên. Nếu thay toàn bộ đường dẫn — đó là di chuyển. Triết lý như Schrödinger: đối tượng vừa di chuyển vừa đổi tên nếu bạn chỉ định đường dẫn mới với tên mới!

2. Di chuyển và đổi tên file: ví dụ

Chúng ta sẽ đi từ đơn giản đến phức tạp và tiếp tục trên nền tảng mini-file-manager của mình.

Phương thức static File.Move

Ví dụ dưới đây cho cách di chuyển (hoặc đổi tên) một file:


// Di chuyển file test1.txt sang thư mục khác với tên mới
File.Move(@"C:\Temp\test1.txt", @"C:\Archive\test1_archived.txt");

Nếu chỉ muốn đổi tên file trong cùng thư mục:


// Chỉ đổi tên file
File.Move(@"C:\Temp\test1.txt", @"C:\Temp\test_renamed.txt");

Đó là toàn bộ phép màu! .NET đơn giản là "cắt" một đường dẫn và "gán" đối tượng đường dẫn khác, nếu cả hai đường dẫn đều khả dụng và không có xung đột.

Phương thức static Directory.Move

Với thư mục — tương tự:


// Di chuyển thư mục
Directory.Move(@"C:\Temp\OldFolder", @"C:\Temp\NewFolder");

Bạn có thể đổi tên thư mục (tên mới trong cùng thư mục cha) hoặc di chuyển toàn bộ sang chỗ khác.

3. Phương thức instance: FileInfo.MoveToDirectoryInfo.MoveTo

Khi bạn đã có object FileInfo hoặc DirectoryInfo, bạn có thể gọi phương thức MoveTo():


var fileInfo = new FileInfo(@"C:\Temp\test1.txt");
fileInfo.MoveTo(@"C:\Archive\test1_archived.txt");

// Thư mục:
var dirInfo = new DirectoryInfo(@"C:\Temp\OldFolder");
dirInfo.MoveTo(@"C:\Temp\NewFolder");

Ở đây cũng vậy: nếu đường dẫn mới là cùng thư mục nhưng tên khác thì xảy ra đổi tên; nếu là thư mục khác — là di chuyển.

4. Còn nếu file đã tồn tại ở nơi đến thì sao?

Đây là lúc phát sinh những nuance mà hay "cắn" bạn vào lúc không ngờ tới.

File.Move

Nếu tại đường dẫn đích đã có file — sẽ ném exception IOException, và code của bạn "sập":


try
{
    File.Move("data.txt", "archive\\data.txt");
}
catch (IOException ex)
{
    Console.WriteLine("Tệp đích đã tồn tại! " + ex.Message);
}

FileInfo.MoveTo

Tình huống y hệt — IOException nếu tệp đích đã tồn tại.

Directory.Move

Với thư mục thì còn nghiêm ngặt hơn: nếu thư mục đích đã tồn tại — sẽ ném exception. Không thể di chuyển thư mục vào vị trí đã bị chiếm.

Bài học: Luôn kiểm tra xem có file hoặc thư mục ở nơi bạn định ghi chưa!


// Kiểm tra an toàn xem có file ở đường dẫn đích không
if (!File.Exists("archive\\data.txt"))
{
    File.Move("data.txt", "archive\\data.txt");
}
else
{
    Console.WriteLine("Tệp đích đã tồn tại!");
}

5. Các nuance hữu ích

Ví dụ đổi tên thư mục


var oldDir = @"C:\Projects\OldReport";
var newDir = @"C:\Projects\NewReport";

// Kiểm tra xem thư mục mới chưa tồn tại và thư mục cũ có tồn tại
if (Directory.Exists(oldDir) && !Directory.Exists(newDir))
{
    Directory.Move(oldDir, newDir);
    Console.WriteLine("Đã đổi tên thư mục thành công.");
}
else
{
    Console.WriteLine("Lỗi: thư mục nguồn không tìm thấy hoặc thư mục mới đã tồn tại.");
}

Đổi tên có tính đến nội dung lồng nhau

Toàn bộ nội dung của thư mục (thư mục con, file) sẽ được di chuyển cùng mà không cần lệnh bổ sung! Rất tiện: chỉ một lệnh là cả cây thư mục được đặt ở chỗ mới.

Best practices và các phương thức hữu dụng của lớp Path

Khi đổi tên hoặc di chuyển file, dùng các phương thức từ lớp System.IO.Path để xây dựng đường dẫn mới hoặc thay đổi tên file một cách chính xác:

  • Lấy tên file không có extension: Path.GetFileNameWithoutExtension(path)
  • Thay đổi chỉ extension: Path.ChangeExtension(path, ".bak")
  • Xây dựng đường dẫn mới với tên khác: Path.Combine(Path.GetDirectoryName(path), "newname.txt")

string oldPath = @"C:\Reports\2023_Final.docx";
string newName = "2023_Archive.docx";
string newPath = Path.Combine(Path.GetDirectoryName(oldPath)!, newName);

File.Move(oldPath, newPath);

6. Những nuance quan trọng và lỗi thường gặp

Quyền truy cập và khóa file

Nếu bạn không có quyền ghi vào một trong các đường dẫn — sẽ ném exception UnauthorizedAccessException. Tương tự, nếu file đang được process khác dùng (ví dụ đang mở trong Word), bạn sẽ gặp lỗi. Đây là trường hợp rất phổ biến.

Di chuyển giữa các ổ đĩa và volume khác nhau

Về cơ bản, File.Move thực hiện thao tác rename nhanh trong cùng một volume/ổ đĩa. Nếu bạn cố di chuyển file từ ổ C sang ổ D — .NET tự động copy rồi xóa file nguồn. Nếu có gì đó sai (ví dụ ổ đích đầy) thì file nguồn sẽ vẫn còn.

Một sự thật thú vị: hầu hết filesystem hiện đại hỗ trợ "rename/di chuyển nhanh" trong cùng volume, còn khi di chuyển giữa volume thì thực hiện copy + delete.

Di chuyển cả thư mục (Directory.Move)

Không thể di chuyển thư mục vào chính nó hoặc vào một thư mục con của nó (ví dụ C:\Data vào C:\Data\Archive) — điều này sẽ gây lỗi.

Làm thế nào để di chuyển an toàn?

Trước mọi thao tác di chuyển, đặc biệt là di chuyển hàng loạt, hãy kiểm tra tồn tại nguồn (File.Exists, Directory.Exists) và không có xung đột ở đích. Và đừng quên dùng try-catch: hệ thống file là một cô nàng capricious, có thể quăng lỗi vào lúc bất ngờ.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION