1. Wprowadzenie
Scenariuszy, kiedy potrzebne są operacje przenoszenia — mnóstwo: przenoszenie "pobranych" plików z tymczasowego folderu do folderu Dokumenty, masowe porządkowanie zdjęć, zmiana nazw według wzorca, przetwarzanie poczty i logów. System plików lubi porządek — albo przynajmniej jego namiastkę! A dobry programista powinien umieć ten porządek wprowadzić.
Do tego często pojawiają się takie zadania na rozmowach kwalifikacyjnych: "Napisz narzędzie, które zmieni nazwy wszystkich plików, dodając do nich numer wersji", albo "Zrób komendę, która przeniesie przestarzałe dokumenty do archiwum". Zobaczmy, jak to zrobić w C#.
Przegląd możliwości
W .NET są dwa główne sposoby na przenoszenie i zmienianie nazw — użyć metod statycznych (File.Move, Directory.Move) albo metod instancyjnych (FileInfo.MoveTo, DirectoryInfo.MoveTo). Wszystkie te metody pod maską robią prawie to samo — różni je głównie składnia.
Jak .NET "widzi" przenoszenie i zmianę nazwy?
Uwaga! Zmiana nazwy i przenoszenie — to w gruncie rzeczy ta sama operacja: plik lub folder w różnych miejscach systemu plików określany jest przez swoją ścieżkę. Jeśli ścieżka się zmienia — uznaje się, że obiekt "został przeniesiony" lub "zmieniono jego nazwę". Jeśli zmieniasz tylko nazwę, ale zostawiasz ten sam katalog — to zmiana nazwy. Jeśli zmieniasz całą ścieżkę — to przeniesienie. Filozofia jak u Schrödingera: obiekt jest i przeniesiony, i przemianowany, jeśli podasz nową ścieżkę z nową nazwą!
2. Przenoszenie i zmiana nazwy plików: przykłady
Będziemy iść od prostego do bardziej skomplikowanego i kontynuujemy na bazie naszego mini-menedżera plików.
Metoda statyczna File.Move
Oto przykład, jak przenieść (albo przemianować) plik:
// Przenosimy plik test1.txt do innego folderu z nową nazwą
File.Move(@"C:\Temp\test1.txt", @"C:\Archive\test1_archived.txt");
A jeśli chcesz po prostu zmienić nazwę pliku w tym samym folderze:
// Po prostu zmieniamy nazwę pliku
File.Move(@"C:\Temp\test1.txt", @"C:\Temp\test_renamed.txt");
I to cała magia! .NET po prostu "obcina" jedną ścieżkę i "przypisuje" obiektowi inną, jeśli obie ścieżki są dostępne i nie ma konfliktów.
Metoda statyczna Directory.Move
Z folderami — analogicznie:
// Przenosimy folder
Directory.Move(@"C:\Temp\OldFolder", @"C:\Temp\NewFolder");
Można zarówno zmieniać nazwę folderu (nowa nazwa w tym samym katalogu), jak i przenosić go w całości w inne miejsce.
3. Metody instancyjne: FileInfo.MoveTo i DirectoryInfo.MoveTo
Gdy masz już obiekt FileInfo albo DirectoryInfo, możesz wywołać metodę MoveTo():
var fileInfo = new FileInfo(@"C:\Temp\test1.txt");
fileInfo.MoveTo(@"C:\Archive\test1_archived.txt");
// Foldery:
var dirInfo = new DirectoryInfo(@"C:\Temp\OldFolder");
dirInfo.MoveTo(@"C:\Temp\NewFolder");
Tutaj też: jeśli nowa ścieżka to ten sam katalog, ale inna nazwa — następuje zmiana nazwy; jeśli inny katalog — przeniesienie.
4. A co jeśli plik już istnieje w miejscu docelowym?
Tu zaczynają się niuanse, które lubią "ukłuć" w najmniej odpowiednim momencie.
File.Move
Jeśli pod wskazaną ścieżką docelową jest już plik — zostanie wyrzucony wyjątek IOException, i twój kod "poleci":
try
{
File.Move("data.txt", "archive\\data.txt");
}
catch (IOException ex)
{
Console.WriteLine("Plik docelowy już istnieje! " + ex.Message);
}
FileInfo.MoveTo
Dokładnie ta sama sytuacja — IOException, jeśli plik docelowy już istnieje.
Directory.Move
W przypadku folderów jest jeszcze ostrzej: jeśli folder docelowy już istnieje — wyjątek. Nie da się przenieść folderu do folderu, który już jest zajęty.
Morał: Zawsze sprawdzaj, czy nie ma już takiego pliku lub folderu tam, gdzie próbujesz zapisać!
// Spokojnie sprawdzamy, czy plik istnieje pod docelową ścieżką
if (!File.Exists("archive\\data.txt"))
{
File.Move("data.txt", "archive\\data.txt");
}
else
{
Console.WriteLine("Plik docelowy już istnieje!");
}
5. Przydatne niuanse
Przykład zmiany nazwy folderu
var oldDir = @"C:\Projects\OldReport";
var newDir = @"C:\Projects\NewReport";
// Sprawdzamy, czy nie ma nowego folderu i czy istnieje stary
if (Directory.Exists(oldDir) && !Directory.Exists(newDir))
{
Directory.Move(oldDir, newDir);
Console.WriteLine("Folder został pomyślnie przemianowany.");
}
else
{
Console.WriteLine("Błąd: folder źródłowy nie znaleziony lub nowy już istnieje.");
}
Zmiana nazwy z uwzględnieniem zawartości zagnieżdżonej
Cała zawartość folderu (podfoldery, pliki) zostanie przeniesiona razem z nim bez dodatkowych poleceń! To wygodne: jedną komendą folder z dowolną zagnieżdżonością trafia w nowe miejsce.
Najlepsze praktyki i przydatne metody klasy Path
Kiedy zmieniasz nazwy lub przenosisz pliki, używaj metod z klasy System.IO.Path, żeby poprawnie zbudować nową ścieżkę lub zmodyfikować nazwę pliku:
- Pobrać nazwę pliku bez rozszerzenia: Path.GetFileNameWithoutExtension(path)
- Zamienić tylko rozszerzenie: Path.ChangeExtension(path, ".bak")
- Zbudować nową ścieżkę z inną nazwą: 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. Ważne niuanse i typowe błędy
Uprawnienia i blokady
Jeśli nie masz uprawnień do zapisu w jednej ze ścieżek — zostanie rzucony wyjątek UnauthorizedAccessException. Podobnie, jeśli plik jest używany przez inny proces (np. otwarty w Word), dostaniesz błąd. To bardzo częsty przypadek.
Przenoszenie między różnymi dyskami i woluminami
W praktyce File.Move realizuje szybką operację zmiany nazwy w obrębie jednego woluminu/dysku. Jeśli spróbujesz przenieść plik z dysku C na dysk D — .NET automatycznie wykona kopiowanie z późniejszym usunięciem pliku źródłowego. Jeśli coś pójdzie nie tak (np. dysk docelowy jest pełny), plik źródłowy pozostanie na miejscu.
Ciekawostka: niemal wszystkie nowoczesne systemy plików wspierają "szybką zmianę nazwy/przeniesienie" wewnątrz woluminu, a przy przenoszeniu między woluminami — kopiowanie + usunięcie.
Przenoszenie całych folderów (Directory.Move)
Nie można przenieść folderu do środka samego siebie ani do folderu w nim zagnieżdżonego (np. C:\Data do C:\Data\Archive) — to spowoduje błąd.
Jak bezpiecznie przenosić?
Przed każdym przeniesieniem, szczególnie masowym, sprawdzaj istnienie źródła (File.Exists, Directory.Exists) i brak konfliktu w miejscu docelowym. I nie zapominaj o try-catch: system plików to kapryśna dama, może rzucić błąd w najmniej oczekiwanym momencie.
GO TO FULL VERSION