File.Move không hoạt động - Tệp đã tồn tại


86

Tôi có một thư mục:

c: \ test

Tôi đang thử mã này:

File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test");

Tôi nhận được ngoại lệ:

Tập tin đã tồn tại

Thư mục đầu ra chắc chắn tồn tại và tệp đầu vào ở đó.


2
Nếu tệp đầu vào đã có trong thư mục đầu ra, thì tệp đó đã tồn tại, do đó giải thích ngoại lệ. Bạn cần chỉ ra rằng bạn muốn tệp gốc được ghi đè bởi tệp mới.
Cody Grey

9
Có vẻ như lỗi đang cho bạn biết chính xác điều gì sai.
Josh

@Josh Không. Có vẻ như Windows đang có hành vi hệ thống tệp không phải POSIX khiến việc tìm ra mẫu / quy trình cập nhật tệp giao dịch di động đơn giản là không thể.
binki

@binki POSIX không liên quan (bạn có muốn nói đến các hoạt động nguyên tử không?), NTFS không hỗ trợ các hoạt động giao dịch thực, như trong rollback-and-get-the-original-file-content-back. Như những người khác đã trả lời, Win32 không cho phép di chuyển với thay thế. Tôi là File.Move của .NET không cung cấp chức năng. Bạn có thể có được cả hai di chuyển với thay thế và các hoạt động giao dịch với các thư viện như AlphaFS
Panagiotis Kanavos

2
@binki trong mọi trường hợp, hành vi được xác định rõ ràng trên các hệ thống tệp khác nhau , bất kể các cuộc thảo luận trên diễn đàn nói gì. Lý do File.Move không gọi các phương thức Ex hoặc Transacted là FAT, không thể bị bỏ qua vì nó vẫn được sử dụng bởi thẻ nhớ, không phải là nguyên tử và không hoạt động giống nhau. Đổi tên không phải là hoạt động siêu dữ liệu và yêu cầu di chuyển dữ liệu thực tế. Và quên đi các giao dịch & copy-on-write. Không phải là một quyết định tuyệt vời
imho

Câu trả lời:


62

Bạn cần phải di chuyển nó sang một tệp khác (thay vì một thư mục), điều này cũng có thể được sử dụng để đổi tên.

Di chuyển:

File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt");

Đổi tên:

File.Move(@"c:\test\SomeFile.txt", @"c:\test\SomeFile2.txt");

Lý do nó cho biết "Tệp đã tồn tại" trong ví dụ của bạn, là vì C:\test\Testcố gắng tạo tệp Testkhông có phần mở rộng, nhưng không thể làm như vậy vì đã tồn tại một thư mục có cùng tên.


138

Những gì bạn cần là:

if (!File.Exists(@"c:\test\Test\SomeFile.txt")) {
    File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt");
}

hoặc là

if (File.Exists(@"c:\test\Test\SomeFile.txt")) {
    File.Delete(@"c:\test\Test\SomeFile.txt");
}
File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt");

Điều này sẽ:

  • Nếu tệp không tồn tại ở vị trí đích, hãy di chuyển tệp thành công hoặc;
  • Nếu tệp tồn tại ở vị trí đích, hãy xóa nó, sau đó di chuyển tệp.

Chỉnh sửa: Tôi nên làm rõ câu trả lời của mình, mặc dù đó là câu trả lời được ủng hộ nhiều nhất! Tham số thứ hai của File.Move phải là tệp đích - không phải là một thư mục. Bạn đang chỉ định tham số thứ hai là thư mục đích, không phải tên tệp đích - đó là những gì File.Move yêu cầu. Vì vậy, tham số thứ hai của bạn nên là c:\test\Test\SomeFile.txt.


Chắc chắn không cần kiểm tra xem tệp không có ở đó hay không, bởi vì anh ta đang kiểm tra và tệp không có ở đó. Ngoại lệ là do không thêm tên tệp vào thư mục đích khi cố gắng di chuyển nó sang một thư mục khác.
Hadi Eskandari

3
Nếu ứng dụng của bạn có nhiều luồng (hoặc có các quy trình khác hoạt động trên tệp của bạn), bạn vẫn có thể nhận được ngoại lệ tương tự ngay cả khi sử dụng mã "if (Exists) Delete". Vì vẫn còn một khoảng thời gian mà một chuỗi / quy trình khác có thể đặt một tệp trở lại sau khi Xóa, nên bạn thực hiện động tác của mình và sau đó vẫn nhận được Ngoại lệ. Đáng ghi nhớ :-)
bytedev

11
Câu trả lời này vẫn có giá trị đối với hầu hết mọi người rằng google sau khi cố gắng ghi đè lên một tệp hiện có. Hầu hết mọi người trong tình trạng khó khăn này không gặp vấn đề về cú pháp / type-o như OP.
WEFX

1
@ v.oddou thật thú vị, nếu tệp không tồn tại, File.Delete thực sự hoạt động chính xác và không làm gì cả. Nếu thay vào đó, bất kỳ thư mục nào trong đường dẫn không tồn tại, bạn sẽ nhận được DirectoryNotFoundException.
Brandon Barkley

2
@JirkaHanika bạn có thể thay đổi if (File.Exists) thành while (File.Exists).
Brandon Barkley

38

Cá nhân tôi thích phương pháp này hơn. Thao tác này sẽ ghi đè lên tệp trên đích, xóa tệp nguồn và cũng ngăn việc xóa tệp nguồn khi sao chép không thành công.

string source = @"c:\test\SomeFile.txt";
string destination = @"c:\test\test\SomeFile.txt";

try
{
    File.Copy(source, destination, true);
    File.Delete(source);
}
catch
{
    //some error handling
}

4
Điều này là tốt cho các tệp nhỏ (và không yêu cầu di chuyển nguyên tử), nhưng đối với các tệp lớn hoặc các trường hợp khi bạn cần chắc chắn rằng bạn sẽ không có các bản sao thì đó là vấn đề.
River Satya

Tại sao bạn thích File.Copy , File.Deletehơn File.Move?
John Pietrar

6
File.Move không có tùy chọn ghi đè.
Mitchell

1
Tùy thuộc vào trường hợp sử dụng của bạn, điều này có thể gây ra sự cố. "Di chuyển" là một sự kiện thực trong trình theo dõi hệ thống tệp. Một cái gì đó liệt kê các sự kiện hệ thống tệp sẽ bị xóa và tạo sự kiện thay vì sự kiện di chuyển. Điều này cũng sẽ thay đổi ID hệ thống tệp cơ bản.
Andrew Rondeau

1
Điều này sẽ không hiệu quả hơn rất nhiều đối với các tệp lớn? Nếu nguồn và đích nằm trên cùng một ổ đĩa vật lý, bạn đang tạo bản sao thứ hai mà không có lý do gì và sau đó xóa bản gốc, trong khi File.Move () sẽ tránh thực hiện thêm công việc nếu nguồn và đích nằm trên cùng một ổ đĩa.
Brad Westness

18

Bạn có thể thực hiện P / Gọi đến MoveFileEx()- vượt qua 11 cho flags( MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
static extern bool MoveFileEx(string existingFileName, string newFileName, int flags);

Hoặc, bạn có thể chỉ cần gọi

Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(existingFileName, newFileName, true);

sau khi thêm Microsoft.VisualBasic làm tham chiếu.


Hoàn toàn tốt nếu ứng dụng chỉ chạy trên Windows. Đây có lẽ là một câu trả lời tốt cho hầu hết những người sẵn sàng dùng thử som P / Invoke.
Todd

9

Nếu tệp thực sự tồn tại và bạn muốn thay thế tệp, hãy sử dụng mã dưới đây:

string file = "c:\test\SomeFile.txt"
string moveTo = "c:\test\test\SomeFile.txt"

if (File.Exists(moveTo))
{
    File.Delete(moveTo);
}

File.Move(file, moveTo);

4

Theo tài liệu cho File.Move không có tham số "ghi đè nếu tồn tại". Bạn đã cố gắng chỉ định thư mục đích , nhưng bạn phải cung cấp thông số kỹ thuật tệp đầy đủ.

Đọc lại tài liệu ("cung cấp tùy chọn để chỉ định tên tệp mới"), tôi nghĩ rằng việc thêm dấu gạch chéo ngược vào thông số thư mục đích có thể hoạt động.


Và các tài liệu đề cập đến Lưu ý rằng nếu bạn cố gắng thay thế một tệp bằng cách di chuyển một tệp cùng tên vào thư mục đó, thì một IOException sẽ được ném ra. Vì mục đích đó, hãy gọi Move(String, String, Boolean)thay thế. nhưng đó có vẻ là một sai lầm?
Kevin Scharnhorst

@KevinScharnhorst Câu trả lời này là năm 2011. Tài liệu hiện bao gồm hỗ trợ .Net Core 3.0 cho Move with Overwrite.
Todd

4

1) Với C # trên .Net Core 3.0 trở lên, bây giờ có một tham số boolean thứ ba:

xem https://docs.microsoft.com/en-us/dotnet/api/system.io.file.move?view=netcore-3.1

In .NET Core 3.0 and later versions, you can call Move(String, String, Boolean) setting the parameter overwrite to true, which will replace the file if it exists.

2) Đối với tất cả các phiên bản khác của .Net, https://stackoverflow.com/a/42224803/887092 là câu trả lời tốt nhất. Sao chép bằng Ghi đè, sau đó xóa tệp nguồn. Điều này tốt hơn vì nó biến nó thành một hoạt động nguyên tử. (Tôi đã cố gắng cập nhật MS Docs bằng cái này)



1

Nếu bạn không có tùy chọn xóa tệp đã tồn tại ở vị trí mới, nhưng vẫn cần di chuyển và xóa khỏi vị trí ban đầu, thủ thuật đổi tên này có thể hoạt động:

string newFileLocation = @"c:\test\Test\SomeFile.txt";

while (File.Exists(newFileLocation)) {
    newFileLocation = newFileLocation.Split('.')[0] + "_copy." + newFileLocation.Split('.')[1];
}
File.Move(@"c:\test\SomeFile.txt", newFileLocation);

Điều này giả định là duy nhất '.' trong tên tệp nằm trước phần mở rộng. Nó chia tệp tin ra làm hai trước phần mở rộng, đính kèm "_copy". ở giữa. Điều này cho phép bạn di chuyển tệp, nhưng tạo bản sao nếu tệp đã tồn tại hoặc bản sao của bản sao đã tồn tại hoặc bản sao của bản sao tồn tại ...;)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.