File.Move Çalışmıyor - Dosya Zaten Var


86

Bir klasörüm var:

c: \ test

Bu kodu deniyorum:

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

İstisna alıyorum:

dosya zaten mevcut

Çıktı dizini kesinlikle var ve girdi dosyası orada.


2
Girdi dosyası zaten çıktı dizinindeyse, o zaman dosya zaten mevcuttur ve istisnayı açıklar. Orijinal dosyanın üzerine yenisi tarafından yazılmasını istediğinizi belirtmeniz gerekir .
Cody Grey

9
Görünüşe göre hata size neyin yanlış olduğunu söylüyor.
Josh

@Josh Hayır. Görünüşe göre Windows, basit bir taşınabilir işlem dosyası güncelleme düzenini / rutini bulmayı imkansız kılan POSIX olmayan dosya sistemi davranışına sahip.
binki

@binki POSIX ilgisizdir ( atomik işlemlerden mi bahsediyorsunuz ?), NTFS , geri alma ve orijinal dosya içeriğini geri alma işlemlerinde olduğu gibi gerçek işlemsel işlemleri destekler. Başkaları cevap olarak, Win32 yapar yerini ile hareket verir. İşlevselliği sağlamayan .NET'in File.Move'iyim. AlphaFS
Panagiotis Kanavos

2
@binki her durumda, forum tartışmaları ne derse desin , davranış farklı dosya sistemlerinde iyi tanımlanmıştır . File.Move Ex veya İşlem Temelli yöntemleri çağırmaz nedeni hala hafıza kartları tarafından kullanılır beri göz ardı edilemeyeceğini FAT, olduğu değil atomik ve gelmez aynı davranırlar. Yeniden adlar, meta veri işlemleri değildir ve gerçek veri hareketini gerektirir. Ve işlemleri ve yazma üzerine kopyalamayı unutun. Harika bir karar imho
Panagiotis Kanavos

Yanıtlar:


62

Onu başka bir dosyaya taşımanız gerekir (bir klasör yerine), bu aynı zamanda yeniden adlandırmak için de kullanılabilir.

Hareket:

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

Adını değiştirmek:

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

Örneğinizde "Dosya zaten var" C:\test\Testifadesinin nedeni Test, uzantı olmadan bir dosya oluşturmaya çalışması , ancak aynı ada sahip bir klasör zaten mevcut olduğundan bunu yapamamasıdır.


139

İhtiyacınız olan şey:

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

veya

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");

Bu ya:

  • Dosya hedef konumda yoksa, dosyayı başarıyla taşıyın veya;
  • Dosya hedef konumda mevcutsa, silin ve ardından dosyayı taşıyın.

Düzenleme: En çok oy alan cevap olmasına rağmen cevabımı netleştirmeliyim! File.Move ikinci parametre olmalıdır hedef dosya - değil bir klasör. İkinci parametreyi hedef klasör olarak belirtiyorsunuz, hedef dosya adı değil - File.Move bunu gerektiriyor. Öyleyse, ikinci parametreniz olmalıdır c:\test\Test\SomeFile.txt.


Kesinlikle dosyanın orada olup olmadığını kontrol etmeye gerek yoktur, çünkü kontrol ediyor ve dosya orada değil. İstisna, dosya adını başka bir klasöre taşımaya çalışırken hedef klasöre eklememekten kaynaklanır.
Hadi Eskandari

3
Uygulamanız çok iş parçacıklıysa (veya dosyalarınızda çalışan başka işlemler varsa), "if (Var) Sil" kodunu kullanarak bile aynı istisnayı yine de alabilirsiniz. Hala başka bir iş parçacığının / işlemin bir dosyayı Silme işleminden sonra geri koyabileceği bir zaman alanı olduğu için, hareketinizi yaparsınız ve sonra yine de İstisnayı alırsınız. Akılda
tutmaya

11
Bu cevap, mevcut bir dosyanın üzerine yazmaya çalıştıktan sonra google'ın kullandığı çoğu kişi için hala geçerlidir. Bu durumdaki çoğu insanın OP gibi bir sözdizimi / tip-o sorunu yoktur.
WEFX

1
@ v.oddou ilginç bir şekilde, eğer dosya yoksa, File.Delete gerçekten düzgün çalışıyor ve hiçbir şey yapmıyor. Bunun yerine, yoldaki dizinlerden herhangi biri yoksa, yine de DirectoryNotFoundException alırsınız.
Brandon Barkley

2
@JirkaHanika if (File.Exists] 'i while (File.Exists) olarak değiştirebilirsiniz.
Brandon Barkley

39

Şahsen ben bu yöntemi tercih ediyorum. Bu, hedefteki dosyanın üzerine yazacak, kaynak dosyayı kaldıracak ve ayrıca kopyalama başarısız olduğunda kaynak dosyanın kaldırılmasını engelleyecektir.

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
Bu, küçük dosyalar için uygundur (ve atomik taşıma gerektirmez), ancak büyük dosyalar veya kopyalarla sonuçlanmayacağınızdan emin olmanız gereken durumlar için sorunludur.
Satya Nehri

Neden tercih edersiniz File.Copy , File.Deleteüzerinde File.Move?
John Pietrar

6
File.Move'un üzerine yazma seçeneği yoktur.
Mitchell

1
Kullanım durumunuza bağlı olarak bu, sorunlara neden olabilir. "Taşı" bir dosya sistemi izleyicisindeki gerçek bir olaydır. Dosya sistemi olaylarını listeleyen bir şey, bir taşıma olayı yerine bir silme ve oluşturma olayı alacak. Bu aynı zamanda temeldeki dosya sistemi kimliğini de değiştirecektir.
Andrew Rondeau

1
Bu, büyük dosyalar için çok daha az performans göstermeyecek mi? Kaynak ve hedef aynı fiziksel birimdeyse, sebepsiz olarak ikinci bir kopya oluşturuyor ve ardından orijinali siliyorsunuz, oysa File.Move () kaynak ve hedef aynı birimdeyse fazladan iş yapmaktan kaçınır.
Brad Westness

18

( ) İçin 11'iMoveFileEx() geçmek için bir P / Çağır yapabilirsinizflagsMOVEFILE_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);

Veya sadece arayabilirsin

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

Microsoft.VisualBasic'i referans olarak ekledikten sonra.


Uygulama yalnızca Windows'ta çalışıyorsa tamamen iyi. Bu muhtemelen bir P / Invoke'u denemeye istekli olan çoğu insan için iyi bir cevaptır.
Todd

9

Dosya gerçekten mevcutsa ve değiştirmek istiyorsanız aşağıdaki kodu kullanın:

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

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

File.Move(file, moveTo);

5

1) .Net Core 3.0 ve ötesinde C # ile, artık üçüncü bir boole parametresi var:

bkz. 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) .Net'in diğer tüm sürümleri için, https://stackoverflow.com/a/42224803/887092 en iyi yanıttır. Overwrite ile kopyalayın, ardından kaynak dosyayı silin. Bu daha iyi çünkü onu atomik bir operasyon yapıyor. (Bununla MS Belgelerini güncellemeye çalıştım)


4

File.Move dokümanlarına göre, "varsa üzerine yazma" parametresi yoktur. Hedef klasörü belirlemeye çalıştınız , ancak tam dosya özelliğini vermeniz gerekiyor.

( "Yeni bir dosya adı belirtmek için seçenek sunan") tekrar docs okuma, ben düşünüyorum çalışabilir hedef klasör spec için ters eğik çizgi ekleyerek.


Ve dokümanlar , aynı isimdeki bir dosyayı bu dizine taşıyarak bir dosyayı değiştirmeye çalışırsanız, bir IOException atılır. Bunun için Move(String, String, Boolean)yerine arayın . ama bu bir hata gibi görünüyor?
Kevin Scharnhorst

@KevinScharnhorst Bu cevap 2011 idi. Dokümantasyon artık Overwrite ile Taşı için .Net Core 3.0 desteğini içeriyor.
Todd


1

Yeni konumda zaten var olan dosyayı silme seçeneğiniz yoksa, ancak yine de orijinal konumundan taşınmanız ve silmeniz gerekiyorsa, bu yeniden adlandırma hilesi işe yarayabilir:

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);

Bu tek '.' dosya adındaki uzantının önünde. Dosyayı uzantıdan önce ikiye böler ve "_copy" ekler. arasında. Bu, dosyayı taşımanıza izin verir, ancak dosya zaten varsa veya kopyanın bir kopyası zaten varsa veya kopyanın bir kopyası varsa bir kopya oluşturur ...;)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.