File.Move ไม่ทำงาน - มีไฟล์อยู่แล้ว


86

ฉันมีโฟลเดอร์:

c: \ test

ฉันกำลังลองใช้รหัสนี้:

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

ฉันได้รับข้อยกเว้น:

มีไฟล์อยู่แล้ว

ไดเร็กทอรีเอาต์พุตมีอยู่แน่นอนและไฟล์อินพุตอยู่ที่นั่น


2
หากไฟล์อินพุตอยู่ในไดเร็กทอรีเอาต์พุตแสดงว่ามีไฟล์อยู่แล้วดังนั้นจึงอธิบายถึงข้อยกเว้น คุณต้องระบุว่าคุณต้องการให้ไฟล์ต้นฉบับถูกเขียนทับด้วยไฟล์ใหม่
โคดี้เกรย์

9
ดูเหมือนว่าข้อผิดพลาดกำลังบอกคุณว่ามีอะไรผิดปกติ
Josh

@ Josh ไม่ดูเหมือนว่า Windows จะมีพฤติกรรมของระบบไฟล์ที่ไม่ใช่ POSIX ซึ่งทำให้การหารูปแบบการอัปเดตไฟล์ธุรกรรมแบบพกพาง่าย ๆ เป็นไปไม่ได้
binki

@binki POSIX ไม่เกี่ยวข้อง (คุณหมายถึงอะตอมดำเนินงาน?), NTFS ไม่สนับสนุนการดำเนินงานการทำธุรกรรมที่แท้จริงในขณะที่ย้อนกลับและได้รับที่เดิมไฟล์เนื้อหากลับ เป็นคนอื่นตอบ Win32 ไม่อนุญาตให้ย้ายกับมาแทนที่ ฉันไม่ใช่ไฟล์ของ. NET ซึ่งไม่มีฟังก์ชันการทำงาน คุณสามารถรับทั้ง Move with replace และการดำเนินการธุรกรรมกับไลบรารีเช่น AlphaFS
Panagiotis Kanavos

2
@binki ไม่ว่าในกรณีใดก็ตามพฤติกรรมนั้นถูกกำหนดไว้อย่างดีบนระบบไฟล์ที่แตกต่างกันไม่ว่าการสนทนาในฟอรัมจะพูดอะไรก็ตาม เหตุผลที่ File.Move ไม่เรียก Ex หรือเมธอด Transacted ก็คือ FAT ซึ่งไม่สามารถเพิกเฉยได้เนื่องจากการ์ดหน่วยความจำยังคงใช้งานอยู่ไม่ใช่ atomic และไม่ทำงานเหมือนเดิม การเปลี่ยนชื่อไม่ใช่การดำเนินการกับข้อมูลเมตาและต้องมีการเคลื่อนย้ายข้อมูลจริง และลืมเกี่ยวกับการทำธุรกรรมและคัดลอกเมื่อเขียน ไม่ใช่การตัดสินใจที่ดี imho
Panagiotis Kanavos

คำตอบ:


62

คุณต้องย้ายไปยังไฟล์อื่น (แทนที่จะเป็นโฟลเดอร์) ซึ่งสามารถใช้เพื่อเปลี่ยนชื่อได้

ย้าย:

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

เปลี่ยนชื่อ:

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

สาเหตุที่ระบุว่า "มีไฟล์อยู่แล้ว" ในตัวอย่างของคุณเป็นเพราะC:\test\Testพยายามสร้างไฟล์ที่Testไม่มีนามสกุล แต่ไม่สามารถทำได้เนื่องจากมีโฟลเดอร์ที่มีชื่อเดียวกันอยู่แล้ว


139

สิ่งที่คุณต้องการคือ:

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

หรือ

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

สิ่งนี้จะ:

  • หากไฟล์ไม่มีอยู่ที่ตำแหน่งปลายทางให้ย้ายไฟล์สำเร็จหรือ;
  • หากไฟล์มีอยู่ที่ตำแหน่งปลายทางให้ลบออกจากนั้นย้ายไฟล์

แก้ไข: ฉันควรชี้แจงคำตอบของฉันแม้ว่าจะมีการโหวตมากที่สุดก็ตาม! พารามิเตอร์ที่สองของ File.Move ควรจะเป็นแฟ้มปลายทาง - ไม่โฟลเดอร์ คุณกำลังระบุพารามิเตอร์ที่สองเป็นโฟลเดอร์ปลายทางไม่ใช่ชื่อไฟล์ปลายทางซึ่งเป็นสิ่งที่ File.Move ต้องการ c:\test\Test\SomeFile.txtดังนั้นพารามิเตอร์ที่สองของคุณควรจะ


ไม่จำเป็นต้องตรวจสอบว่าไม่มีไฟล์อยู่ที่นั่นอย่างแน่นอนเพราะเขากำลังตรวจสอบและไม่มีไฟล์อยู่ที่นั่น ข้อยกเว้นเกิดจากการไม่ต่อท้ายชื่อไฟล์ไปยังโฟลเดอร์ปลายทางเมื่อพยายามย้ายไปยังโฟลเดอร์อื่น
Hadi Eskandari

3
หากแอปของคุณเป็นแบบมัลติเธรด (หรือมีกระบวนการอื่น ๆ ที่ทำงานกับไฟล์ของคุณ) คุณอาจยังคงได้รับข้อยกเว้นเหมือนเดิมแม้ว่าจะใช้โค้ด "if (Exists) Delete" เนื่องจากยังมีช่องว่างที่เธรด / กระบวนการอื่นสามารถใส่ไฟล์กลับหลัง Delete ได้คุณจึงทำการย้ายแล้วรับ Exception ต่อไป คุ้มค่าแค่นึกถึง :-)
bytedev

11
คำตอบนี้ยังใช้ได้สำหรับคนส่วนใหญ่ที่ google หลังจากพยายามเขียนทับไฟล์ที่มีอยู่ คนส่วนใหญ่ในสถานการณ์นี้ไม่มีปัญหาเกี่ยวกับไวยากรณ์ / ประเภท -o เช่น OP
WEFX

1
@ v.oddou น่าสนใจถ้าไม่มีไฟล์ File.Delete ทำงานได้อย่างถูกต้องและไม่ทำอะไรเลย หากไม่มีไดเร็กทอรีใด ๆ ในพา ธ แทนคุณจะได้รับ DirectoryNotFoundException
Brandon Barkley

2
@JirkaHanika คุณสามารถเปลี่ยนได้ถ้า (File.Exists) เป็น while (File.Exists)
Brandon Barkley

39

โดยส่วนตัวแล้วฉันชอบวิธีนี้ การดำเนินการนี้จะเขียนทับไฟล์ที่ปลายทางลบไฟล์ต้นทางและป้องกันการลบไฟล์ต้นทางเมื่อคัดลอกล้มเหลว

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
วิธีนี้ใช้ได้ดีสำหรับไฟล์ขนาดเล็ก (และไม่มีข้อกำหนดสำหรับการย้ายอะตอม) แต่สำหรับไฟล์ขนาดใหญ่หรือในกรณีที่คุณต้องแน่ใจว่าคุณจะไม่ลงเอยด้วยการซ้ำกันมันเป็นปัญหา
แม่น้ำสัตยา

ทำไมคุณถึงชอบFile.Copy , File.Deleteมากกว่าFile.Move?
John Pietrar

6
File.Move ไม่มีตัวเลือกการเขียนทับ
Mitchell

1
อาจทำให้เกิดปัญหาขึ้นอยู่กับกรณีการใช้งานของคุณ "ย้าย" เป็นเหตุการณ์จริงในโปรแกรมเฝ้าดูระบบไฟล์ รายการบางอย่างไปยังเหตุการณ์ระบบไฟล์จะได้รับการลบและสร้างเหตุการณ์แทนเหตุการณ์การย้าย นอกจากนี้ยังจะเปลี่ยน ID ระบบไฟล์พื้นฐาน
Andrew Rondeau

1
สิ่งนี้จะมีประสิทธิภาพน้อยกว่าสำหรับไฟล์ขนาดใหญ่หรือไม่? หากต้นทางและปลายทางอยู่ในฟิสิคัลวอลุ่มเดียวกันคุณกำลังสร้างสำเนาที่สองโดยไม่มีเหตุผลจากนั้นจึงลบต้นฉบับในขณะที่ File.Move () จะหลีกเลี่ยงการทำงานพิเศษหากต้นทางและปลายทางอยู่ในไดรฟ์ข้อมูลเดียวกัน
Brad Westness

18

คุณสามารถทำ P / Invoke to MoveFileEx()- pass 11สำหรับ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);

หรือโทร

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

หลังจากเพิ่ม Microsoft.VisualBasic เป็นข้อมูลอ้างอิง


ใช้ได้ดีหากแอปทำงานบน Windows เท่านั้น นี่คงเป็นคำตอบที่ดีสำหรับคนส่วนใหญ่ที่อยากลองเล่น Som P / Invoke
ทอดด์

9

หากไฟล์มีอยู่จริงและคุณต้องการแทนที่ให้ใช้รหัสด้านล่าง:

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) ด้วย C # บน. Net Core 3.0 ขึ้นไปตอนนี้มีพารามิเตอร์บูลีนตัวที่สาม:

ดู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 เวอร์ชันอื่น ๆ ทั้งหมดhttps://stackoverflow.com/a/42224803/887092เป็นคำตอบที่ดีที่สุด คัดลอกด้วยการเขียนทับจากนั้นลบไฟล์ต้นฉบับ สิ่งนี้ดีกว่าเพราะมันทำให้เป็นการทำงานของอะตอม (ฉันได้พยายามอัปเดต MS Docs ด้วยสิ่งนี้)


4

ตามเอกสารสำหรับ File.Moveไม่มีพารามิเตอร์ "เขียนทับถ้ามีอยู่" คุณพยายามระบุโฟลเดอร์ปลายทางแต่คุณต้องระบุข้อมูลจำเพาะของไฟล์ทั้งหมด

การอ่านเอกสารอีกครั้ง ("ให้ตัวเลือกในการระบุชื่อไฟล์ใหม่") ฉันคิดว่าการเพิ่มแบ็กสแลชลงในข้อมูลจำเพาะของโฟลเดอร์ปลายทางอาจใช้งานได้


และเอกสารกล่าวถึง โปรดทราบว่าหากคุณพยายามแทนที่ไฟล์โดยการย้ายไฟล์ที่มีชื่อเดียวกันไปยังไดเร็กทอรีนั้น IOException จะถูกโยนทิ้ง เพื่อจุดประสงค์นั้นให้โทรหาMove(String, String, Boolean)แทน แต่ดูเหมือนจะเป็นความผิดพลาด?
Kevin Scharnhorst

@KevinScharnhorst คำตอบนี้คือปี 2011 ขณะนี้เอกสารประกอบด้วยการรองรับ. Net Core 3.0 สำหรับ Move with Overwrite
ทอดด์

2

ลองMicrosoft.VisualBasic.FileIO.FileSystem.MoveFile(Source, Destination, True). พารามิเตอร์สุดท้ายคือสวิตช์เขียนทับซึ่งSystem.IO.File.Moveไม่มี


2
มีคำตอบอื่นอยู่แล้วที่นี่ที่คล้ายกันซึ่งแนะนำstackoverflow.com/a/42224803/1236734
JG

นี่คือคำตอบที่แนะนำเหมือนกัน: stackoverflow.com/a/38372760/887092ไม่ใช่ stackoverflow.com/a/42224803/1236734
Todd

1

หากคุณไม่มีตัวเลือกในการลบไฟล์ที่มีอยู่แล้วในตำแหน่งใหม่ แต่ยังคงต้องย้ายและลบจากตำแหน่งเดิมเคล็ดลับการเปลี่ยนชื่อนี้อาจใช้ได้ผล:

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

สิ่งนี้ถือว่าเป็นเพียง "." ในชื่อไฟล์อยู่ก่อนนามสกุล มันแยกไฟล์ออกเป็นสองไฟล์ก่อนส่วนขยายแนบ "_copy" ในระหว่าง. วิธีนี้ช่วยให้คุณสามารถย้ายไฟล์ แต่จะสร้างสำเนาหากไฟล์มีอยู่แล้วหรือมีสำเนาของสำเนาอยู่แล้วหรือมีสำเนาของสำเนาอยู่ ... ;)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.