C# File.Move creates an empty file and IO exception - c#

My code processes a video file (using ffmpeg) and creates different qualities (360p, 480p, etc) and formats (mp4 and HLS) of that. After creating these files, I move all of them to another drive (a network location).
my code looks Like this:
var files = Directory.GetFiles(srcFolder);
string filename, destFile = string.Empty, srcFile = string.Empty;
try
{
for (int i = 0; i < files.Length; i++)
{
srcFile = files[i];
filename = Path.GetFileName(srcFile);
destFile = Path.Combine(destFolder, filename);
File.Move(srcFile, destFile);
}
}
catch
{
_logger.LogError("Error in moving file. srcFile: {0}, destFile: {1}", destFile, srcFile);
throw;
}
This process works fine most of the time, but for some files, I get an IO exception every time I run this process.
System.IO.IOException: The file exists. at System.IO.FileSystem.MoveFile(String sourceFullPath, String destFullPath, Boolean overwrite)
I made sure that destFolder does not exist before, nor did the destFile.
After logging the error and finding the path of source and target files, I downloaded both of them. The source file is a .ts file with a size of 1,048 KB, and the target file is an empty file with the same name (0KB).
This error happened multiple times with the same video, so I assume that it has something to do with the file itself. But I cannot figure it out.

Related

System.IO.IOException: Cannot create a file when that file already exists. Even after deleting the existing file

Using .NET Core 3.1 and C#, I'm trying to move a directory (including all subdirectories and files) to another directory. The destination directory may contain folders and files that already exist with the same name as the source directory, for example "source/folder/file.txt" may already exist in "destination/folder/file.txt" but I would like to overwrite everything in the destination directory.
The error I am getting is "System.IO.IOException: Cannot create a file when that file already exists.", however I am deleting the file that already exists in the destination before moving the file from the source (File.Delete before File.Move), so I don't understand why I am getting this error. Also to add, I am not able to reproduce this error 100% of the time for some reason.
This is the code I am using to move a directory (lines 137 - 155):
public static void MoveDirectory(string source, string target)
{
var sourcePath = source.TrimEnd('\\', ' ');
var targetPath = target.TrimEnd('\\', ' ');
var files = Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories)
.GroupBy(s => Path.GetDirectoryName(s));
foreach (var folder in files)
{
var targetFolder = folder.Key.Replace(sourcePath, targetPath);
Directory.CreateDirectory(targetFolder);
foreach (var file in folder)
{
var targetFile = Path.Combine(targetFolder, Path.GetFileName(file));
if (File.Exists(targetFile)) File.Delete(targetFile);
File.Move(file, targetFile);
}
}
Directory.Delete(source, true);
}
This is the stack trace of my error:
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.IOException: Cannot create a file when that file already exists.
at System.IO.FileSystem.MoveFile(String sourceFullPath, String destFullPath, Boolean overwrite)
at Module_Installer.Classes.Bitbucket.MoveDirectory(String source, String target) in F:\git\module-installer\module-installer\Module Installer\Classes\Bitbucket.cs:line 147
at Module_Installer.Classes.Bitbucket.DownloadModuleFiles(Module module, String username, String password, String workspace, String repository, String commitHash, String versionNumber, String downloadDirectory, String installDirectory) in F:\git\module-installer\module-installer\Module Installer\Classes\Bitbucket.cs:line 113
at Module_Installer.Classes.OvernightInstall.ProcessInstalledModule(TenantModule tenantModule, Boolean skipBackup) in F:\git\module-installer\module-installer\Module Installer\Classes\OvernightInstall.cs:line 393
at Module_Installer.Classes.OvernightInstall.Run(Boolean skipBackup) in F:\git\module-installer\module-installer\Module Installer\Classes\OvernightInstall.cs:line 75
at Module_Installer.Program.Main(String[] args) in F:\git\module-installer\module-installer\Module Installer\Program.cs:line 40
This error is happening when I am running the application via Windows Task Scheduler, which I have set to run at 03:30am every day, I have specified that the task should "Start In" the same folder as where the EXE is located.
Any suggestions would be appreciated, thanks!
Instead of deleting existing files in the target directory try to overwrite them using File.Move(file, targetFile, overwrite: true).
By the way there is an MSDN example on how to copy directories. It's not exactly your use case, but could be helpful anyway.

C# ASP System.IO.Compression - Unauthorized access exception when using zipArchive.CreateEntryFromFile for multiple files()

I have the following lines of code that work for creating a zip using ZipFile.CreateFromDirectory(selectedFile, zipPath)
if (selectedFolder == string.Empty)
{
Console.WriteLine("Invalid folder, try again");
}
else
{
Console.WriteLine("\nSelect zipfile name: ");
var zipName = Console.ReadLine();
// Also available: extractToDirectory
var zipPath = #"C:\Users\User\Documents\Dev\" + zipName + ".zip";
ZipFile.CreateFromDirectory(selectedFolder, zipPath);
However, the following code which should for all intents and purposes do the same thing except for multiple files being archived into a single zip folder refuses to work:
public static void CreateZipFile(string folderToCreateZip, IEnumerable<string> files)
{
var zipPath = folderToCreateZip + "\\test6.zip";
// Create a new ZIP in this location
using (var zip = ZipFile.Open(zipPath, ZipArchiveMode.Create))
{
foreach (var file in files)
{
// Add entry for files
zip.CreateEntryFromFile(file, zipPath, CompressionLevel.Optimal);
}
}
// Dispose of zip object after files have been zipped
//zip.Dispose();
}
var zip == ZipArchive zip
I've tried disabling read-only mode on the folders where the zip should get created, but I don't think this matters since the prior function with CreateFromDirectory() works fine. I've also tried creating a ZIP on desktop, but I get the same error.
This is the exception I'm getting:
As a note, I noticed that it does initially create the zip despite this error, just that it cannot add anything to it unlike CreateFromDirectory() can due to the folder either being in use, no permissions to that area or the folder already existing. Is there a way I can get CreateEntryFromFile() working or an alternative that would work for multiple files?
I had the same problem. The solution was post the full path name at the destinationArchiveFileName parameter (and also a write alowed path). For example c:\my apps folder\my app\my temp\zipfile.zip

Unzip not replacing file

I have a problem with a zip file replacing an existing file. I have looked at other examples on here and I still can't seem to figure it out...
I have a loop that writes some stats of the file extracted into a textbox. I think that its this line:
if (!System.IO.File.Exists(fileUnzipFullName))
My Code:
public void UnzipFileNew()
{
richTextBox1.AppendText("\r\n" + "EXTRACTING!");
String rootpath = Environment.CurrentDirectory;
//This stores the path where the file should be unzipped to,
//including any subfolders that the file was originally in.
string fileUnzipFullPath;
//This is the full name of the destination file including
//the path
string fileUnzipFullName;
//Opens the zip file up to be read
using (ZipArchive archive = ZipFile.OpenRead(#"update.zip"))
{
//Loops through each file in the zip file
foreach (ZipArchiveEntry file in archive.Entries)
{
//Outputs file information to the Textbox
richTextBox1.AppendText("\r\n");
richTextBox1.AppendText("File Name: "+ file.Name);
richTextBox1.AppendText("\r\n");
richTextBox1.AppendText("File Size: bytes "+ file.Length);
richTextBox1.AppendText("\r\n");
richTextBox1.AppendText("Compression Ratio: "+ ((double)file.CompressedLength / file.Length).ToString("0.0%"));
richTextBox1.AppendText("\r\n");
//Identifies the destination file name and path
fileUnzipFullName = Path.Combine(rootpath, file.FullName); //fileUnzipFullName = Path.Combine(#"Example\", file.FullName);
//Extracts
if (!System.IO.File.Exists(fileUnzipFullName))
{
fileUnzipFullPath = Path.GetDirectoryName(fileUnzipFullName);
//Creates the directory if it doesn't exist
Directory.CreateDirectory(fileUnzipFullPath);
//Extracts the file to (potentially new) path
file.ExtractToFile(fileUnzipFullName);
}
}
}
}
if (!System.IO.File.Exists(fileUnzipFullName)) will indeed prevent you even trying to extract the file if it already exists. So you will need to remove this or change it as per your use case.
Additionally, the ExtractToFile method will throw an IOException if the file already exists as you are using it. Fortunately, MSDN reveals that there is an overload with a boolean flag for overwriting:
public static void ExtractToFile(
this ZipArchiveEntry source,
string destinationFileName,
bool overwrite
)
So instead of
file.ExtractToFile(fileUnzipFullName);
use
file.ExtractToFile(fileUnzipFullName, true);
Using your code, this will indiscriminately overwrite all files with the ones extracted from the zip:
//Extracts
//if (!System.IO.File.Exists(fileUnzipFullName))
//{
fileUnzipFullPath = Path.GetDirectoryName(fileUnzipFullName);
//Creates the directory if it doesn't exist
Directory.CreateDirectory(fileUnzipFullPath);
//Extracts the file to (potentially new) path
file.ExtractToFile(fileUnzipFullName, true);
//}

File.Replace throws ERROR_UNABLE_TO_MOVE_REPLACEMENT

I have a 'safe' config file saving routine that tries to be atomic when writing user config data to the disk, avoiding disk caching etc.
The code goes something like this:
public static void WriteAllTextSafe(string path, string contents)
{
// generate a temp filename
var tempPath = Path.GetTempFileName();
// create the backup name
var backup = path + ".backup";
// delete any existing backups
if (File.Exists(backup))
File.Delete(backup);
// get the bytes
var data = Encoding.UTF8.GetBytes(contents);
if (File.Exists(path))
{
// write the data to a temp file
using (var tempFile = File.Create(tempPath, 4096, FileOptions.WriteThrough))
tempFile.Write(data, 0, data.Length);
// replace the contents
File.Replace(tempPath, path, backup, );
}
else
{
// if the file doesn't exist we can't replace so just write it
using (var tempFile = File.Create(path, 4096, FileOptions.WriteThrough))
tempFile.Write(data, 0, data.Length);
}
}
On most systems this works perfectly and I have not had any reports of issues, but for some users each time my program calls this function they get the following error:
System.IO.IOException: 置換するファイルを置換されるファイルに移動できません。置換されるファイルの名前は、元のままです。
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.InternalReplace(String sourceFileName, String destinationFileName, String destinationBackupFileName, Boolean ignoreMetadataErrors)
at download.ninja.BO.FileExtensions.WriteAllTextSafe(String path, String contents)
at download.ninja.BO.FileExtensions.SaveConfig(String path, Object toSave)
After a bit of investigation and with the help of Google Translate I've found that the actual error is thrown from the wine32 ReplaceFile function:
ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176 (0x498)
The replacement file could not be renamed. If lpBackupFileName was specified, the replaced and
replacement files retain their original file names. Otherwise, the replaced file no longer exists
and the replacement file exists under its original name.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365512(v=vs.85).aspx
The problem is that I have no idea why Windows is throwing this error.. I have tried setting the file to readonly locally but that throws an Unauthorized exception rather than a IOException so I don't believe that is causing the problem.
My second guess is that the the is somehow locked, but I only have one read function that is used for reading all config files and that should be closing off all file handles when it finsihes
public static T LoadJson<T>(string path)
{
try
{
// load the values from the file
using (var r = new StreamReader(path))
{
string json = r.ReadToEnd();
T result = JsonConvert.DeserializeObject<T>(json);
if (result == null)
return default(T);
return result;
}
}
catch (Exception)
{
}
return default(T);
}
I have also tried throwing fake exceptions in the LoadJson function to try and lock the file but I can't seem to do it.
Even then I have tried simulating a file lock by opening the file in a different process and running the save code while it is still open, and that generates a different (expected) error:
System.IO.IOException: The process cannot access the file because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.InternalReplace(String sourceFileName, String destinationFileName, String destinationBackupFileName, Boolean ignoreMetadataErrors)
at download.ninja.BO.FileExtensions.WriteAllTextSafe(String path, String contents)
So the question is.. what is causing Windows to throw this ERROR_UNABLE_TO_MOVE_REPLACEMENT error on some systems
NOTE: This error is thrown EVERY TIME my program attempt to replace the file on an affected machine.. not just occasionally.
OK, so found the problem. It seems that files passed into ReplaceFile must be on the SAME DRIVE
In this case the user had changed their temp folder to d:\tmp\
So File.Replace looked something like this:
File.Replace(#"D:\tmp\sometempfile", #"c:\AppData\DN\app-config", #"c:\AppData\DN\app-config.backup");
This difference in drives between the source file and the desitnation file in File.Replace seems to be what caused the problem.
I have modified my WriteAllTextSafe function as follows and my user reports the problem has been resolved!
public static void WriteAllTextSafe(string path, string contents)
{
// DISABLED: User temp folder might be on different drive
// var tempPath = Path.GetTempFileName();
// use the same folder so that they are always on the same drive!
var tempPath = Path.Combine(Path.GetDirectoryName(path), Guid.NewGuid().ToString());
....
}
As far as I can find there is no documentation stating that the two files need to be on the same drive but I can reproduce the problem by manually entering different drives (yet valid paths) into File.Replace
Are you by any chance, hardcoding drives in your file name, e.g. c:\ etc?
If you are, don't, they might not not work in runtimes where the locale is 1041 (japanese).
Instead use the framework to get the drive part and dynamically build your path.
string drivePath = System.IO.Path.GetPathRoot(System.Environment.SystemDirectory);
string somePath = string.Concat(drivePath, "someFolder\SomeFileName.Txt");
I've had the same problem working with source files on OneDrive copying to local files under %AppData%. A solution that worked well for me was to delete the destination file then perform a copy from the source.
Code that does not work:
file.replace(source,destination,backup,false)
Code that does work:
File.Delete(destination)
File.Copy(source, destination)

Copy and overwrite files between two folders(one shared)

I'm making a small application that have to take all the files from a shared folder and copy them in the current folder(the once from where the application it's runned).
One month ago this code was fine:
string seprin_address = #"\\PC-SEPRIN\2port\";
SimpleCopy(seprin_address);
public void SimpleCopy(string sourcePath){
try{
string fileName = "";
string targetPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
bool path = false;
string real_target = "";
for(int i = 0; i < targetPath.Length; i++){
if(targetPath[i] == 'C'){
path = true;
}
if(path){
real_target += targetPath[i];
}
}
// Use Path class to manipulate file and directory paths.
string sourceFile = System.IO.Path.Combine(sourcePath, fileName);
string destFile = System.IO.Path.Combine(targetPath, fileName);
// To copy a folder's contents to a new location:
// Create a new target folder, if necessary.
/*if (!System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
}*/
// To copy a file to another location and
// overwrite the destination file if it already exists.
//System.IO.File.Copy(sourceFile, destFile, true);
// To copy all the files in one directory to another directory.
// Get the files in the source folder. (To recursively iterate through
// all subfolders under the current directory, see
// "How to: Iterate Through a Directory Tree.")
// Note: Check for target path was performed previously
// in this code example.
if (System.IO.Directory.Exists(sourcePath))
{
string[] files = System.IO.Directory.GetFiles(sourcePath);
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
// Use static Path methods to extract only the file name from the path.
fileName = System.IO.Path.GetFileName(s);
destFile = System.IO.Path.Combine(targetPath, fileName);
System.IO.File.Copy(s, destFile, true);
}
}
else
{
MessageBox.Show("Error");
}
// Keep console window open in debug mode.
}
catch(Exception e_p){
lbabel.Text = e_p.Message;
}
}
Now i get the "URI not supported error" when the file.copy it's called.
I think its supernatural but if you have any other ideas i'm all ears.
I would find out if the URI not supported is complaining about source or destination. I would also check to make sure the user that this is running as has permission to the directories in question. Could the users permissions have changed? I have had occasion where I had jobs in scheduled tasks where the user was set and later the password was changed for the user but not on the scheduled task. The same could be true if this is written as a service with a specific user.
as you are saying it was working fine one month ago, there can be two possibilities which is restricting you from accessing the Path.
1.Remote PC Hostname PC-SEPRIN might havebeen changed.Please check the remote pc hostname.
2.check the Shared Folder 2port path properly.
if somebody changes shared folder name or deletes it, you can not access it.
and also please check whether you have permissions to access it or not.

Categories

Resources