File.Move Tidak Berfungsi - File Sudah Ada

86

Saya punya folder:

c: \ test

Saya mencoba kode ini:

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

Saya mendapatkan pengecualian:

File sudah ada

Direktori keluaran pasti ada dan file masukan ada di sana.

Jack Kada
sumber
2
Jika file input sudah ada di direktori output, maka file tersebut sudah ada, sehingga menjelaskan pengecualiannya. Anda perlu menunjukkan bahwa Anda ingin file asli ditimpa dengan yang baru.
Cody Gray
9
Sepertinya kesalahan memberi tahu Anda apa yang salah.
Josh
@ Josh Tidak. Sepertinya Windows memiliki perilaku sistem file non-POSIX yang membuat penentuan pola / rutinitas pembaruan file transaksional portabel tidak mungkin dilakukan.
binki
@binki POSIX tidak relevan (yang Anda maksud untuk atom operasi?), NTFS tidak mendukung operasi transaksi nyata, seperti di rollback-dan-get-the-asli-file-konten-kembali. Seperti orang lain menjawab, Win32 tidak memungkinkan bergerak dengan mengganti. Itu File NET. Pindah yang tidak menyediakan fungsionalitas. Anda bisa mendapatkan Pindah dengan operasi ganti dan transaksional dengan pustaka seperti AlphaFS
Panagiotis Kanavos
2
@binki dalam hal apapun perilakunya didefinisikan dengan baik pada sistem file yang berbeda , tidak peduli apa forum diskusi katakan. Alasan File.Move tidak memanggil metode Ex atau Transacted adalah karena FAT, yang tidak dapat diabaikan karena masih digunakan oleh kartu memori, tidak atomic dan tidak berperilaku sama. Mengganti nama bukanlah operasi metadata dan membutuhkan pergerakan data yang sebenarnya. Dan lupakan transaksi & copy-on-write. Bukan keputusan yang bagus imho
Panagiotis Kanavos

Jawaban:

62

Anda perlu memindahkannya ke file lain (bukan folder), ini juga dapat digunakan untuk mengganti nama.

Pindah:

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

Ganti nama:

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

Alasan yang dikatakan "File sudah ada" dalam contoh Anda, adalah karena C:\test\Testmencoba membuat file Testtanpa ekstensi, tetapi tidak dapat melakukannya karena folder dengan nama yang sama sudah ada.

Lee
sumber
139

Yang Anda butuhkan adalah:

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

atau

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

Ini akan:

  • Jika file tidak ada di lokasi tujuan, berhasil memindahkan file, atau;
  • Jika file memang ada di lokasi tujuan, hapus, lalu pindahkan file tersebut.

Sunting: Saya harus mengklarifikasi jawaban saya, meskipun itu yang paling disukai! Parameter kedua dari File.Move harus menjadi file tujuan - bukan folder. Anda menentukan parameter kedua sebagai folder tujuan, bukan nama file tujuan - yang dibutuhkan oleh File.Move. Jadi, parameter kedua Anda seharusnya c:\test\Test\SomeFile.txt.

Jamie Howarth
sumber
Tentu tidak perlu mengecek apakah file tersebut tidak ada, karena dia sedang memeriksa dan file tersebut tidak ada. Pengecualian ini disebabkan oleh tidak menambahkan nama file ke folder tujuan saat mencoba memindahkannya ke folder lain.
Hadi Eskandari
3
Jika aplikasi Anda multi utas (atau ada proses lain yang bekerja pada file Anda), Anda mungkin masih bisa mendapatkan pengecualian yang sama bahkan menggunakan kode "jika (Ada) Hapus". Karena masih ada ruang waktu di mana utas / proses lain dapat meletakkan file kembali setelah Hapus, maka Anda melakukan pemindahan, dan kemudian mendapatkan Pengecualian. Perlu diingat :-)
bytedev
11
Jawaban ini masih berlaku untuk kebanyakan orang setelah google mencoba untuk menimpa file yang sudah ada. Kebanyakan orang dalam keadaan sulit ini tidak memiliki masalah sintaks / tipe-o seperti OP.
WEFX
1
@ v.oddou menariknya, jika file tidak ada, File.Delete memang bekerja dengan benar dan tidak melakukan apa-apa. Jika sebaliknya, salah satu direktori di jalur tidak ada, Anda akan mendapatkan DirectoryNotFoundException.
Brandon Barkley
2
@JirkaHanika Anda dapat mengubah jika (File.Exists) menjadi sementara (File.Exists).
Brandon Barkley
39

Secara pribadi saya lebih suka metode ini. Ini akan menimpa file di tujuan, menghapus file sumber dan juga mencegah penghapusan file sumber saat penyalinan gagal.

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
}
Mitchell
sumber
4
Ini bagus untuk file kecil (dan tidak ada persyaratan untuk pemindahan atom), tetapi untuk file besar, atau kasus ketika Anda perlu memastikan bahwa Anda tidak akan mendapatkan duplikat, itu bermasalah.
Sungai Satya
Mengapa Anda lebih memilih File.Copy , File.Deletelebih File.Move?
John Pietrar
6
File.Move tidak memiliki opsi timpa.
Mitchell
1
Bergantung pada kasus penggunaan Anda, ini dapat menyebabkan masalah. "Pindah" adalah peristiwa nyata dalam pengamat sistem file. Sesuatu yang dicantumkan ke peristiwa sistem file akan mendapatkan peristiwa penghapusan dan pembuatan, bukan peristiwa pemindahan. Ini juga akan mengubah ID sistem file yang mendasarinya.
Andrew Rondeau
1
Bukankah ini akan jauh lebih buruk performanya untuk file besar? Jika sumber dan tujuan berada pada volume fisik yang sama, Anda membuat salinan kedua tanpa alasan dan kemudian menghapus aslinya, sedangkan File.Move () akan menghindari melakukan pekerjaan tambahan jika sumber dan tujuan berada pada volume yang sama.
Brad Westness
18

Anda dapat melakukan P / Invoke untuk MoveFileEx()- lulus 11 untuk 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);

Atau, Anda bisa menelepon

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

setelah menambahkan Microsoft.VisualBasic sebagai referensi.

mheyman
sumber
Benar-benar baik-baik saja jika aplikasi hanya berjalan di Windows. Ini mungkin jawaban yang bagus untuk kebanyakan orang yang ingin mencoba som P / Invoke.
Todd
9

Jika file benar-benar ada dan Anda ingin menggantinya gunakan kode di bawah ini:

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

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

File.Move(file, moveTo);
Pawel Czapski
sumber
5

1) Dengan C # pada .Net Core 3.0 dan seterusnya, sekarang ada parameter boolean ketiga:

lihat 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) Untuk semua versi .Net lainnya, https://stackoverflow.com/a/42224803/887092 adalah jawaban terbaik. Salin dengan Timpa, lalu hapus file sumber. Ini lebih baik karena menjadikannya operasi atom. (Saya telah mencoba memperbarui MS Docs dengan ini)

Todd
sumber
4

Menurut dokumen untuk File.Move, tidak ada parameter "timpa jika ada". Anda mencoba menentukan folder tujuan , tetapi Anda harus memberikan spesifikasi file yang lengkap.

Membaca dokumen lagi ("memberikan opsi untuk menentukan nama file baru"), menurut saya , menambahkan garis miring terbalik ke spesifikasi folder tujuan mungkin berhasil.

Ekkehard. Sudut
sumber
Dan dokumen menyebutkan Perhatikan bahwa jika Anda mencoba mengganti file dengan memindahkan file dengan nama yang sama ke direktori itu, IOException dilempar. Untuk tujuan itu, hubungi Move(String, String, Boolean)saja. tapi sepertinya itu salah?
Kevin Scharnhorst
@KevinScharnhorst Jawaban ini tahun 2011. Dokumentasi sekarang menyertakan dukungan .Net Core 3.0 untuk Move with Overwrite.
Todd
2

Coba Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(Source, Destination, True). Parameter terakhir adalah sakelar Timpa, yang System.IO.File.Movetidak memiliki.

Menandai
sumber
2
Ada jawaban lain yang sudah ada di sini yang serupa yang menyarankan stackoverflow yang
sama.com/a/42224803/1236734
Ini adalah jawaban yang menyarankan hal yang sama: stackoverflow.com/a/38372760/887092 , bukan stackoverflow.com/a/42224803/1236734
Todd
1

Jika Anda tidak memiliki opsi untuk menghapus file yang sudah ada di lokasi baru, tetapi masih perlu memindahkan dan menghapus dari lokasi asli, trik mengganti nama ini mungkin berhasil:

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

Ini mengasumsikan satu-satunya '.' di nama file sebelum ekstensi. Ini membagi file menjadi dua sebelum ekstensi, melampirkan "_copy." diantara. Ini memungkinkan Anda memindahkan file, tetapi membuat salinan jika file sudah ada atau salinan salinan sudah ada, atau salinan salinannya sudah ada ...;)

Mengoleng
sumber