Se o arquivo de entrada já está no diretório de saída, então o arquivo já existe, explicando a exceção. Você precisa indicar que deseja que o arquivo original seja sobrescrito pelo novo.
Cody Gray
9
Parece que o erro está dizendo exatamente o que está errado.
Josh
@Josh Não. Parece que o Windows está tendo um comportamento de sistema de arquivos não POSIX, o que torna impossível descobrir um padrão / rotina simples de atualização de arquivo transacional portátil.
binki
@binki POSIX é irrelevante (você está se referindo a operações atômicas ?), o NTFS oferece suporte a operações transacionais reais, como rollback-and-get-the-original-file-content-back. Como outros respondeu: Win32 faz permitir movimento com substituir. É o File.Move do .NET que não fornece a funcionalidade. Você pode obter o Move com substituição e operações transacionais com bibliotecas como AlphaFS
Panagiotis Kanavos
2
@binki em qualquer caso, o comportamento é bem definido em diferentes sistemas de arquivos , não importa o que as discussões do fórum digam. A razão de File.Move não chamar os métodos Ex ou Transacted é que o FAT, que não pode ser ignorado porque ainda é usado por cartões de memória, não é atômico e não se comporta da mesma forma. Renomeações não são operações de metadados e requerem movimentação real de dados. E esqueça as transações e a cópia na gravação. Não é uma boa decisão imho
Panagiotis Kanavos
Respostas:
62
Você precisa movê-lo para outro arquivo (em vez de uma pasta), isso também pode ser usado para renomear.
O motivo pelo qual diz "Arquivo já existe" em seu exemplo é porque C:\test\Testtenta criar um arquivo Testsem uma extensão, mas não consegue porque já existe uma pasta com o mesmo nome.
if (!File.Exists(@"c:\test\Test\SomeFile.txt")) {
File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt");
}
ou
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");
Isso irá:
Se o arquivo não existir no local de destino, mova o arquivo com êxito ou;
Se o arquivo existir no local de destino, exclua-o e mova o arquivo.
Edit: Devo esclarecer minha resposta, embora seja a mais votada! O segundo parâmetro de File.Move deve ser o arquivo de destino - não uma pasta. Você está especificando o segundo parâmetro como a pasta de destino, não o nome do arquivo de destino - que é o que File.Move requer. Portanto, seu segundo parâmetro deve ser c:\test\Test\SomeFile.txt.
Certamente não precisa verificar se o arquivo não está lá, porque ele está verificando e o arquivo não está lá. A exceção é causada por não anexar o nome do arquivo à pasta de destino ao tentar movê-lo para outra pasta.
Hadi Eskandari
3
Se o seu aplicativo for multiencadeado (ou houver outros processos trabalhando em seus arquivos), você ainda poderá obter a mesma exceção, mesmo usando o código "if (Exists) Delete". Como ainda há um espaço de tempo em que outro processo / thread pode colocar um arquivo de volta após a exclusão, então você faz sua movimentação e obtém a exceção de qualquer maneira. Vale a pena ter em mente :-)
bytedev
11
Esta resposta ainda é válida para a maioria das pessoas que pesquisam no Google depois de tentar substituir um arquivo existente. A maioria das pessoas nessa situação não tem um problema de sintaxe / tipo-o como o OP.
WEFX de
1
@ v.oddou curiosamente, se o arquivo não existe, File.Delete realmente funciona corretamente e não faz nada. Se, em vez disso, qualquer um dos diretórios no caminho não existir, você obterá uma DirectoryNotFoundException.
Brandon Barkley de
2
@JirkaHanika você pode alterar if (File.Exists) para while (File.Exists).
Brandon Barkley de
38
Pessoalmente, prefiro esse método. Isso substituirá o arquivo no destino, removerá o arquivo de origem e também impedirá a remoção do arquivo de origem quando a cópia falhar.
Isso é bom para arquivos pequenos (e não há necessidade de movimentação atômica), mas para arquivos grandes, ou casos em que você precisa ter certeza de que não ficará com duplicatas, é problemático.
Rio Satya de
Por que você prefere File.Copy , File.Deletemais File.Move?
John Pietrar,
6
File.Move não tem uma opção de substituição.
Mitchell,
1
Dependendo do seu caso de uso, isso pode causar problemas. "Mover" é um evento real em um observador de sistema de arquivos. Algo listando os eventos do sistema de arquivos obterá um evento de exclusão e criação em vez de um evento de movimentação. Isso também mudará o ID do sistema de arquivos subjacente.
Andrew Rondeau
1
Isso não terá um desempenho muito menor para arquivos grandes? Se a origem e o destino estiverem no mesmo volume físico, você está criando uma segunda cópia sem motivo e, em seguida, excluindo o original, enquanto File.Move () evitará trabalho extra se a origem e o destino estiverem no mesmo volume.
Brad Westness
18
Você pode fazer um P / Invoke para MoveFileEx()- passar 11 para flags( MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)
Totalmente bem se o aplicativo estiver rodando apenas no Windows. Esta é provavelmente uma boa resposta para a maioria das pessoas que desejam experimentar o P / Invoke.
Todd
9
Se o arquivo realmente existe e você deseja substituí-lo, use o código abaixo:
De acordo com os documentos para File.Move, não há parâmetro "sobrescrever se existir". Você tentou especificar a pasta de destino , mas deve fornecer a especificação completa do arquivo.
Lendo os documentos novamente ("fornecendo a opção de especificar um novo nome de arquivo"), eu acho , adicionar uma barra invertida às especificações da pasta de destino pode funcionar.
E os documentos mencionam. Observe que se você tentar substituir um arquivo movendo um arquivo com o mesmo nome para esse diretório, uma IOException é lançada. Para isso, ligue Move(String, String, Boolean). mas isso parece ser um erro?
Kevin Scharnhorst
@KevinScharnhorst Esta resposta foi 2011. A documentação agora inclui suporte para .Net Core 3.0 para Mover com Substituição.
Todd
4
1) Com C # no .Net Core 3.0 e além, agora há um terceiro parâmetro booleano:
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) Para todas as outras versões do .Net, https://stackoverflow.com/a/42224803/887092 é a melhor resposta. Copie com sobrescrever e exclua o arquivo de origem. Isso é melhor porque torna uma operação atômica. (Eu tentei atualizar o MS Docs com isso)
Experimente Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(Source, Destination, True). O último parâmetro é a opção Overwrite, que System.IO.File.Movenão tem.
Se você não tem a opção de excluir o arquivo já existente no novo local, mas ainda precisa mover e excluir do local original, este truque de renomeação pode funcionar:
Isso pressupõe o único '.' no nome do arquivo está antes da extensão. Ele divide o arquivo em dois antes da extensão e anexa "_copy". entre. Isso permite que você mova o arquivo, mas cria uma cópia se o arquivo já existe ou uma cópia da cópia já existe, ou uma cópia da cópia da cópia existe ...;)
Respostas:
Você precisa movê-lo para outro arquivo (em vez de uma pasta), isso também pode ser usado para renomear.
Mover:
File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt");
Renomear:
File.Move(@"c:\test\SomeFile.txt", @"c:\test\SomeFile2.txt");
O motivo pelo qual diz "Arquivo já existe" em seu exemplo é porque
C:\test\Test
tenta criar um arquivoTest
sem uma extensão, mas não consegue porque já existe uma pasta com o mesmo nome.fonte
O que você precisa é:
if (!File.Exists(@"c:\test\Test\SomeFile.txt")) { File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt"); }
ou
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");
Isso irá:
Edit: Devo esclarecer minha resposta, embora seja a mais votada! O segundo parâmetro de File.Move deve ser o arquivo de destino - não uma pasta. Você está especificando o segundo parâmetro como a pasta de destino, não o nome do arquivo de destino - que é o que File.Move requer. Portanto, seu segundo parâmetro deve ser
c:\test\Test\SomeFile.txt
.fonte
Pessoalmente, prefiro esse método. Isso substituirá o arquivo no destino, removerá o arquivo de origem e também impedirá a remoção do arquivo de origem quando a cópia falhar.
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 }
fonte
File.Copy , File.Delete
maisFile.Move
?Você pode fazer um P / Invoke para
MoveFileEx()
- passar 11 paraflags
(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);
Ou você pode apenas ligar
Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(existingFileName, newFileName, true);
após adicionar Microsoft.VisualBasic como uma referência.
fonte
Se o arquivo realmente existe e você deseja substituí-lo, use o código abaixo:
string file = "c:\test\SomeFile.txt" string moveTo = "c:\test\test\SomeFile.txt" if (File.Exists(moveTo)) { File.Delete(moveTo); } File.Move(file, moveTo);
fonte
De acordo com os documentos para File.Move, não há parâmetro "sobrescrever se existir". Você tentou especificar a pasta de destino , mas deve fornecer a especificação completa do arquivo.
Lendo os documentos novamente ("fornecendo a opção de especificar um novo nome de arquivo"), eu acho , adicionar uma barra invertida às especificações da pasta de destino pode funcionar.
fonte
Move(String, String, Boolean)
. mas isso parece ser um erro?1) Com C # no .Net Core 3.0 e além, agora há um terceiro parâmetro booleano:
consulte 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) Para todas as outras versões do .Net, https://stackoverflow.com/a/42224803/887092 é a melhor resposta. Copie com sobrescrever e exclua o arquivo de origem. Isso é melhor porque torna uma operação atômica. (Eu tentei atualizar o MS Docs com isso)
fonte
Experimente
Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(Source, Destination, True)
. O último parâmetro é a opção Overwrite, queSystem.IO.File.Move
não tem.fonte
Se você não tem a opção de excluir o arquivo já existente no novo local, mas ainda precisa mover e excluir do local original, este truque de renomeação pode funcionar:
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);
Isso pressupõe o único '.' no nome do arquivo está antes da extensão. Ele divide o arquivo em dois antes da extensão e anexa "_copy". entre. Isso permite que você mova o arquivo, mas cria uma cópia se o arquivo já existe ou uma cópia da cópia já existe, ou uma cópia da cópia da cópia existe ...;)
fonte