FileInfo unable to find specified file exception - c#

I have what could be an unusual problem. My problem is that I have a collection of file paths which contain the filenames too. As the code loops round the collection it takes the string and creates a FileInfo object. With this object it then uses the MoveTo method to move the file to another location.
This all works well until it reaches a file with a zero length and says it cannot find the file. If I take this file and create a FileInfo object in a different application it works regardless of size. Does anyone know about what is causing this and how to solve it? Relevant code snippet below
IList<string> files = new List<string >();
files.add(file1);
files.add(file2);
foreach (string filepath in files)
{
FileInfo file = new FileInfo (filepath);
string newlocation = Path.Combine(dest, file.name);
file.MoveTo (newlocation); //exception thrown here on zero length
}

Try to call file.Refresh() before file.MoveTo(...).
Read Remarks in this page https://msdn.microsoft.com/en-us/library/system.io.fileinfo.exists.aspx

you need to use
System.IO.File.Move(Sourcefile, DestinationFile);
More details:https://msdn.microsoft.com/en-us/library/system.io.file.move(v=vs.110).aspx

Related

Created ZIP archive is invalid

I'm using ZipFile.Open() to create an archive, then adding entries using CreateEntryFromFile(). The resulting file is invalid according to Windows. 7-zip can open the file, but only part of the files are listed.
The code looks like this:
using (ZipArchive archive = ZipFile.Open(archivePath, ZipArchiveMode.Create))
{
while (reader.Read())
{
object myValue = reader.GetValue(0);
string objectId = myValue.ToString();
string objectPath = Path.Combine(myPath, objectId);
string[] files = Directory.GetFiles(objectPath);
if (files.Length > 0)
{
archive.CreateEntryFromFile(files[0], Path.GetFileName(files[0]));
}
}
}
As you can see, I do dispose of the ZipArchive when I'm done, and unlike every other question about this problem, I don't use any streams, so there's nothing to flush.
Anyone know what's wrong?
It could be possible that the file being added to the archive is being used by another process and cannot be accessed. To avoid this, you can try wrapping the CreateEntryFromFile method in a try-catch block and handle the IOException that could be thrown if the file is in use. You can also try closing any streams or file handles that may have been opened on the file before adding it to the archive.

moving file from one location to another without knowing file name

One of my executable process produces two files. I want to move one file that is produced to shared drive. I am writing an automatic process to move the file from one location to shared drive. The only issue is file name changes every time the executable is run so I don't have the exact filename with me. I only have the extension, .xls. I have only one .xls file in my directory.
I tried doing this
File.Copy(#"*.xls", #"\\serv44\Application\testing\name\test2\*.xls", true);
It threw an error saying Invalid name. After moving the file to shared drive. I want to delete the .xls file.
File.Delete("*.xls");
any help will be appreciated
You should get file name and then do whatever you want with that file. I.e. if you have only one xls file in the source directory:
var targetDirectory = #"\\serv44\Application\testing\name\test2\";
var sourceFile = Directory.EnumerateFiles(sourceDirectory, "*.xls").FirstOrDefault();
if (sourceFile != null)
{
var sourceFileName = Path.GetFileName(sourceFile);
var targetFileName = Path.Combine(targetDirectory, sourceFileName);
File.Copy(sourceFileName, targetFileName);
File.Delete(sourceFileName);
}
Note: instead of copy and delete you can use single Move operation.
If you want to move several files from your source directory, then instead of taking first one process all found files in a loop:
foreach(var sourceFile in Directory.EnumerateFiles(sourceDirectory, "*.xls"))
{
var sourceFileName = Path.GetFileName(sourceFile);
var targetFileName = Path.Combine(targetDirectory, sourceFileName);
File.Move(sourceFileName, targetFileName);
}
This should give you that file name:
var fileName = Directory.GetFiles(yourDirectory, "*.xls").ToList().FirstOrDefault();

ZipArchive.CreateEntryFromFile does not show new entry

I'm experiencing a strange issue here and not quite sure what I'm missing. I ran the code below and it did create a .zip file and I watched the size increase from 0KB to 8,992KB. However, as I open the .zip file, I don't see any file. And if I try to "Extract All..." from explorer, it shows "Windows can not complete the extraction" because the .zip file "is invalid". Any idea what I did wrong?
if (File.Exists(ZipName))
File.Delete(ZipName);
using (ZipArchive archive = ZipFile.Open(ZipName, ZipArchiveMode.Create))
{
foreach (string sFileName in FileNames)
{
archive.CreateEntryFromFile(sFileName,sFileName,CompressionLevel.Optimal);
}
}
You need to strip the drive letter from the entryName, which is the 3rd parameter to CreateEntryFromFile().
So instead of
archive.CreateEntryFromFile(sFileName, sFileName, CompressionLevel.Optimal);
Use
archive.CreateEntryFromFile(sFileName, sFileName.Substring(3), CompressionLevel.Optimal);
I ran into the same problem, and I discovered a solution. It turns out that I was feeding the method a full path to the file for both filename arguments, like so:
// This gets a list of files with their full paths
var fileList = Directory.GetFiles(_outputDir, "*.txt");
foreach (var file in fileList)
{
archive.CreateEntryFromFile(file, file, CompressionLevel.Optimal);
}
That gave me the same problem you had -- an empty zip file, which was invalid. (By the say, my file paths weren't that long -- they were C:\Results\[some_guid].txt.)
The solution was to get the files as FileInfo objects, then for the first argument use the full path and for the second argument just use the file name, like so:
// This gets a set of FileInfo objects, with a FullName property that is
// the full path to the file, and a Name property that is just the file name.
var directoryInfo = new DirectoryInfo(_outputDir);
var fileList = directoryInfo.GetFiles("*.txt");
foreach (var file in fileList)
{
archive.CreateEntryFromFile(file.FullName, file.Name, CompressionLevel.Optimal);
}
This ended up working perfectly. If I opened the zip file, the files were there. If I extracted it, the extraction worked and the files seemed to be valid.

How to use Thread Pool and Mutex in c#?

I try to learn how to use Thread Pool and Mutex, as a practice I'm trying to make an application that copy files from one path in the computer to another path in the computer.
To do this application I used Thread Pool (so a few copies could happen simultaneously):
object[] paths = new object [2]; // The source path and the destination path
string[] files[] = System.IO.Directory.GetFiles(sourceFolderPath); //string sourceFolderPath = Folder path that contains the files
foreach(string s in files)
{
paths[0] = s; // The file source - s = the file name with the file path;
paths[1] = s.Replace(sourceFolderPath, destFolderPath); // Replaces between the source folder and the destination folder but keeps the file name
ThreadPool.QueueUserWorkItem(new waitCallback(CopyFIle), paths);
}
So far, the application sends each one of the files to the function that copy the file from the source folder to the destination folder.
The CopyFile function looks like this:
static void CopyFiles(object paths)
{
object[] temp = paths as object[]; // The casting to object array
string sourcePath = temp[0].ToString();
string destPath = temp[1].ToString();
System.IO.File.Copy(filePath, destPath, true); // The copy from the source to the dest
}
The weird thing is that when I run the application it throws an exception: "The process cannot access to the file 'C:..........' because it is being used by another process".
When I try to find out the mistake and I run the application step by step the application run properly and the whole files are copied from the source folder to the destination folder.
That case made me think that maybe the fact that I'm using ThreadPool made a two threads or more to open the same file (the thing that should not happen because I used foreach and each one of the files paths is transferred as a parameter only once).
To solve this I tried to use Mutex and now the CopyFile function looks like this:
static Mutex mutex = new Mutex();
static void CopyFiles(object paths)
{
Mutex.WaitOne(); //Waits until the critical section is free from other threads
try
{
object[] temp = paths as object[]; // The casting to object array
string sourcePath = temp[0].ToString();
string destPath = temp[1].ToString();
System.IO.File.Copy(filePath, destPath, true); // The copy from the source to the dest
}
Finally
{
Mutex.ReleaseMutex(); //Release the critical area
}
}
Now the application should wait until the critical area is free and just then try to copy the file so the exception: "The process cannot access to the file 'C:..........' because it is being used by another process" should not appear.
As I thought, the exception did not appear but the application copied only one file from the source folder to the destination folder and not all of the files.
When I tried to run this application step by step the same weird thing happened and everything went properly, all of the files were copied to the destination folder.
Why this is happen? And how can I solve this problem so all the files will be copied to the destination folder in a normal application running and not step by step?
Your problem isn't the ThreadPool. What goes wrong is the argument.
In your first code-snippet, you fill an object-array with two argument-values and pass that to the Queue-method. What happens here is, that you use always the same array. So in the first iteration of your foreach-loop, you write two values into the array, pass it. Eventually, the method gets executed be the ThreadPool, using that object-array. In the same time, in the second iteration of the foreach-loop, you write again into that exact array and pass it again to the ThreadPool. That means, two (or more) Threads are starting to work on that array.
You don't know when the CopyFiles-method is active, so you can't tell when the array was unboxed and is ready for re-usage. That could be achieved using a mutual exclusion (the easiest way in C# is using the lock-keyword), but that's not the way you should use here.
The better way would be to create new object-arrays each iteration of the foreach-loop. Simply change the code to:
string[] files[] = System.IO.Directory.GetFiles(sourceFolderPath); //string sourceFolderPath = Folder path that contains the files
foreach(string s in files)
{
object[] paths = new object [2]; // The source path and the destination path
paths[0] = s; // The file source - s = the file name with the file path;
paths[1] = s.Replace(sourceFolderPath, destFolderPath); // Replaces between the source folder and the destination folder but keeps the file name
ThreadPool.QueueUserWorkItem(new waitCallback(CopyFIle), paths);
}

Copy and paste a file programmaticaly

Question Background:
I need to copy and paste (move) a file from one folder location to another.
Issue:
The File.Copy method of System.IO requires the that both parameters are of known file locations. I only know one file path location - in this case localDevPath. localQAPath is the folder path where I want the copied file to be moved too.
string localDevPath = #"C:\Folder1\testFile.cs";
string localQaPath = #"C:\Folder2\";
File.Copy(localDevPath, localQaPath);
Can anyone tell me how to go about carrying out this 'copy and paste' method I'm trying to implement.
string localDevPath = #"C:\Folder1\testFile.cs";
string localQaPath = #"C:\Folder2\";
FileInfo fi = new FileInfo(localDevPath);
fi.MoveTo(Path.Combine(localQaPath, fi.Name));
Assuming that these are user-provided paths and you can't simply include the filename in the second path, then you need to extract the last path element from localDevPath and then add it to localQaPath. You could probably do that with Path.GetFilename.
I'm guessing the issue here is that the filename is variable, in which case, you could do something like this to extract the filename from the full path of localDevPath:
string localDevPath = #"C:\Folder1\testFile.cs";
string localQaPath = #"C:\Folder2\";
string[] tokens = localDevPath.Split(#"\");
localQaPath += tokens[tokens.Length-1];
File.Copy(localDevPath, localQaPath);
Documentation on File.Copy is on MSDN. There is an overload that accepts a boolean, to allow overwriting if there is a naming conflict.
If what you want to do is move the file from one location to another, the method you are looking for is MoveTo. It is a method of the FileInfo class. There is a very complete example in the MSDN Library here: FileInfo.MoveTo Example

Categories

Resources