getting file name and moving it - c#

string fName = Path.GetFileName(tempPaths[z]);
if (!File.Exists(subAch + fName))
{
File.Move(tempPaths[z], subAch + fName);
Console.WriteLine("moved!!! from " + tempPaths[z] + " tooooo ");
}
tempPaths is a list with all the image file paths. e.g. ./images/image4.jpg
subAch is a directory string.
I wish to get the file name of the file then move them to another directory. But with the code above i kept getting error: file is being used by other process.
Is there anyway which get the file name and move them? I have tried fileStream but was confused by it.
Please advice.
Thank you!

Your code should work just fine. You just need to figure out who is locking the files.
I'd put the code inside the if-block in a try-catch block to deal with the locked files.
I will also recommend you to use Path.Combine instead of dir + file.
One thing: you are checking if subAch + tempPaths[z] exists, yet you are copying to a different location; subAch + fName.

File is being used by another process means exactly that. Someone/something is already using the file, so can't move it. You can always catch the error and moving everything else?

I have use a non-ideal way to grab the file name and move the files to another place.
tempPaths.AddRange(Directory.GetFiles(rawStorePath, filter, SearchOption.AllDirectories));
The code above gets all the directories of all the files in the folder set. The outcome with be something like this. tempPaths is a List.
"./images/glass_numbers_5.jpg"
"./images/G.JPG"
"./images/E.JPG"
"./images/F.JPG"
"./images/glass_numbers_0.jpg"
"./images/C.JPG"
"./images/B.JPG"
"./images/A.JPG"
"./images/D.JPG"
"./images/glass_numbers_7.jpg"
then after i use a loop to grab the file names.
for (int i = 0; i < tempPaths.Count; i++)
{
//Getting the original names of the images
int pLength = rawStorePath.Length;
string something = tempPaths[i].Remove(0, pLength);
if (!_tfileName.ContainsKey(tempPaths[i]))
{ _tfileName.Add(tempPaths[i], something); }
}
rawStorePath is the path of the targeted path e.g.: ./images/
tempPath[i] e.g. : ./images/G.JPG
So with the length i remove the letters and get the file name back.
Please advice me for a ideal way to do this if there is any.
Thanks!

Related

.NET File Access Violation

I feel kind of stupid posting this, but it seems like a genuine issue that I've made sufficiently simple so as to demonstrate that it should not fail. As part of my work I am responsible for maintaining build systems that take files under version control, and copy them to other locations. Sounds simple, but I've constantly experienced file access violations when attempting to copy files that I've supposedly already set as 'Normal'.
The code sample below simply creates a set of test files, makes them read only, and then copies them over to another folder. If the files already exist in the destination folder, the RO attribute is cleared so that the file copy will not fail.
The code works to a point, but at seemingly random points an exception is thrown when the file copy is attempted. The code is all single threaded, so unless .NET is doing something under the hood that causes a delay on the setting of attributes I can't really explain the problem.
If anyone can explain why this is happening I'd be interested. I'm not looking for a solution unless there is something I am definitely doing wrong, as I've handled the issue already, I'm just curious as no one else seems to have reported anything related to this.
After a few iterations I get something like:
A first chance exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll
Additional information: Access to the path 'C:\TempFolderB\TEMPFILENAME8903.txt' is denied.
One other fact, if you get the file attributes BEFORE the file copy, the resulting state says the file attributes indeed Normal, yet examination of the local file shows it as Read Only.
/// <summary>
/// Test copying multiple files from one folder to another while resetting RO attr
/// </summary>
static void MultiFileCopyTest()
{
/// Temp folders for our test files
string folderA = #"C:\TempFolderA";
string folderB = #"C:\TempFolderB";
/// Number of files to create
const int fileCount = 10000;
/// If the test folders do not exist populate them with some test files
if (System.IO.Directory.Exists(folderA) == false)
{
const int bufferSize = 32768;
System.IO.Directory.CreateDirectory(folderA);
System.IO.Directory.CreateDirectory(folderB);
byte[] tempBuffer = new byte[bufferSize];
/// Create a bunch of files and make them all Read Only
for (int i = 0; i < fileCount; i++)
{
string filename = folderA + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";
if (System.IO.File.Exists(filename) == false)
{
System.IO.FileStream str = System.IO.File.Create(filename);
str.Write(tempBuffer, 0, bufferSize);
str.Close();
}
/// Ensure files are Read Only
System.IO.File.SetAttributes(filename, System.IO.FileAttributes.ReadOnly);
}
}
/// Number of iterations around the folders
const int maxIterations = 100;
for (int idx = 0; idx < maxIterations; idx++)
{
Console.WriteLine("Iteration {0}", idx);
/// Loop for copying all files after resetting the RO attribute
for (int i = 0; i < fileCount; i++)
{
string filenameA = folderA + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";
string filenameB = folderB + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";
try
{
if (System.IO.File.Exists(filenameB) == true)
{
System.IO.File.SetAttributes(filenameB, System.IO.FileAttributes.Normal);
}
System.IO.File.Copy(filenameA, filenameB, true);
}
catch (System.UnauthorizedAccessException ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
(This isn't a full answer, but I don't have enough reputation yet to post comments...)
I don't think you are doing anything wrong, when I run your test code I can reproduce the problem every time. I have never got past 10 iterations without the error occurring.
I did a further test, which might shed some light on the issue:
I set all of the files in TempFolderA to hidden.
I then ensured all of the files in TempFolderB were NOT hidden.
I put a break-point on Console.WriteLine(ex.Message)
I ran the code, if it got past iteration 1 then I stopped, reset the hidden attributes and ran again.
After a couple of tries, I got a failure in the 1st iteration so I opened Windows Explorer on TempFolderB and scrolled down to the problematic file.
The file was 0 bytes in size, but had RHA attributes set.
Unfortunately I have no idea why this is. Process Monitor doesn't show any other activity which could be relevant.
Well, right in the documentation for the System.IO.File.SetAttributes(string path, System.IO.FileAttributes attributes) method, I found the following:
Exceptions:
System.UnauthorizedException:
path specified a file that is read-only.
-or- This operation is not supported on the current platform.
-or- The caller does not have the required permission.
So, if I had to guess, the file in the destination (e.g. filenameB) did in fact already exist. It was marked Read-Only, and so, the exception was thrown as per the documentation above.
Instead, what you need to do is remove the Read-Only attribute via an inverse bit mask:
if (FileExists(filenameB))
{
// Remove the read-only attribute
FileAttributes attributes = File.GetAttributes(filenameB);
attributes &= ~FileAttributes.ReadOnly;
File.SetAttributes(filenameB, attributes);
// You can't OR the Normal attribute with other attributes--see MSDN.
File.SetAttributes(filenameB, FileAttributes.Normal);
}
To be fair, the documentation on the SetAttributes method isn't real clear about how to go about setting file attributes once a file is marked as Readonly. Sure, there's an example (using the Hidden attribute), but they don't explicitly say that you need to use an inverted bitmask to remove the Hidden or Readonly attributes. One could easily assume it's just how they chose to "unset" the attribute. It's also not clear from the documentation about what would happen, for instance, if you marked the file thusly:
File.SetAttributes(pathToFile, FileAttributes.Normal);
File.SetAttributes(pathToFile, FileAttributes.Archived);
Does this result in the file first having Normal attributes set, then only Archived, or does it result in the file having Normal set, and then _additionallyhavingArchived` set, resulting in a Normal, but Archived file? I believe it's the former, rather than the latter, based on how attributes are "removed" from a file using the inverted bitmask.
If anyone finds anything contrary, please post a comment and I'll update my answer accordingly.
HTH.
This may cause because user don't have sufficient permission to access file system ,
work around :
1,Try to run application in administrative mode
OR
2,Try to run visual studio in administrative mode (if you are using debugger)

"Could not find a part of the path" error message

I am programming in c# and want to copy a folder with subfolders from a flash disk to startup.
Here is my code:
private void copyBat()
{
try
{
string source_dir = "E:\\Debug\\VipBat";
string destination_dir = "C:\\Users\\pc\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup";
if (!System.IO.Directory.Exists(destination_dir))
{
System.IO.Directory.CreateDirectory(destination_dir);
}
// Create subdirectory structure in destination
foreach (string dir in Directory.GetDirectories(source_dir, "*", System.IO.SearchOption.AllDirectories))
{
Directory.CreateDirectory(destination_dir + dir.Substring(source_dir.Length));
}
foreach (string file_name in Directory.GetFiles(source_dir, "*.*", System.IO.SearchOption.AllDirectories))
{
File.Copy(file_name, destination_dir + file_name.Substring(source_dir.Length), true);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message, "HATA", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
I got an error:
Could not find a part of the path E:\Debug\VipBat
The path you are trying to access is not present.
string source_dir = "E:\\Debug\\VipBat\\{0}";
I'm sure that this is not the correct path. Debug folder directly in E: drive looks wrong to me. I guess there must be the project name folder directory present.
Second thing; what is {0} in your string. I am sure that it is an argument placeholder because folder name cannot contains {0} such name. So you need to use String.Format() to replace the actual value.
string source_dir = String.Format("E:\\Debug\\VipBat\\{0}",variableName);
But first check the path existence that you are trying to access.
There's something wrong. You have written:
string source_dir = #"E:\\Debug\\VipBat\\{0}";
and the error was
Could not find a part of the path E\Debug\VCCSBat
This is not the same directory.
In your code there's a problem, you have to use:
string source_dir = #"E:\Debug\VipBat"; // remove {0} and the \\ if using #
or
string source_dir = "E:\\Debug\\VipBat"; // remove {0} and the # if using \\
Is the drive E a mapped drive? Then, it can be created by another account other than the user account. This may be the cause of the error.
I had the same error, although in my case the problem was with the formatting of the DESTINATION path. The comments above are correct with respect to debugging the path string formatting, but there seems to be a bug in the File.Copy exception reporting where it still throws back the SOURCE path instead of the DESTINATION path. So don't forget to look here as well.
-TC
Probably unrelated, but consider using Path.Combine instead of destination_dir + dir.Substring(...). From the look of it, your .Substring() will leave a backlash at the beginning, but the helper classes like Path are there for a reason.
There can be one of the two cause for this error:
Path is not correct - but it is less likely as CreateDirectory should create any path unless path itself is not valid, read invalid characters
Account through which your application is running don't have rights to create directory at path location, like if you are trying to create directory on shared drive with not enough privileges etc
File.Copy(file_name, destination_dir + file_name.Substring(source_dir.Length), true);
This line has the error because what the code expected is the directory name + file name, not the file name.
This is the correct one
File.Copy(source_dir + file_name, destination_dir + file_name.Substring(source_dir.Length), true);
We just had this error message occur because the full path was greater than 260 characters -- the Windows limit for a path and file name. The error message is misleading in this case, but shortening the path solved it for us, if that's an option.
I resolved a similar issue by simply restarting Visual Studio with admin rights.
The problem was because it couldn't open one project related to Sharepoint without elevated access.
This could also be the issue: Space in the folder name
Example:
Let this be your path:
string source_dir = #"E:\Debug\VipBat";
If you try accessing this location without trying to check if directory exists, and just in case the directory had a space at the end, like :
"VipBat    ", instead of just "VipBat" the space at the end will not be visible when you see in the file explorer.
So make sure you got the correct folder name and dont add spaces to folder names. And a best practice is to check if folder exists before you keep the file there.

Directory.Move(): Access to Path is Denied

I'm writing this Windows Form Application in Visual Studio 2010 using C#.
There is a Execute button on the form, the user will hit the button, the program will generate some files and are stored in the Output folder (which is created by the program using Directory.CreateDirectory())
I want to create an Archive folder to save the output files from previous runs.
In the beginning of each run, I try to move the existing Output folder to the Archive folder, then create a new Output folder. Below is the function I ran to move directory.
static void moveToArchive()
{
if (!Directory.Exists("Archive")) Directory.CreateDirectory("Archive");
string timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
try
{
Directory.Move("Output", "Archive\\" + timestamp);
}
catch(Exception e)
{
Console.WriteLine("Can not move folder: " + e.Message);
}
}
The problem I ran into confuses me a lot...
There are some times that I can successfully move the Output folder to archive, but sometimes it fails.
The error message I got from catching the exception is Access to path 'Output' is denied.
I have checked that all the files in the Output folder are not in use. I don't understand how access is denied sometimes and not all the times.
Can someone explain to me and show me how to resolve the problem?
--Edit--
After HansPassant comment, I modified the function a little to get the current directory and use the full path. However, I'm still having the same issue.
The function now looks like this:
static void moveToArchive()
{
string currentDir = Environment.CurrentDirectory;
Console.WriteLine("Current Directory = " + currentDir);
if (!Directory.Exists(currentDir + "\\Archive")) Directory.CreateDirectory(currentDir + "\\Archive");
string timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
try
{
Directory.Move(currentDir + "\\Output", currentDir + "\\Archive\\" + timestamp);
}
catch(Exception e)
{
Console.WriteLine("Can not move folder: " + e.Message);
}
}
I printed out the current directory and it is just as what I was expecting, and I'm still having trouble using full path. Access to path 'C:\Users\Me\Desktop\FormApp\Output' is denied.
--Edit--
Thank you everyone for answering and commenting.
I think some of you miss this part so I'm going stress it a bit more.
The Directory.Move() sometimes work and sometimes fails.
When the function succeed, there was no problem. Output folder is moved to Archive
When the function fails, the exception message I got was Access to path denied.
Thank you all for the replies and help. I have figured out what the issue was.
It is because there was a file that's not completely closed.
I was checking the files that were generated, and missed the files the program was reading from.
All files that were generated were closed completely. It was one file I used StreamReader to open but didn't close. I modified the code and am now not having problem, so I figure that's were the issue was.
Thanks for all the comments and answers, that definitely help me with thinking and figuring out the problem.
See http://windowsxp.mvps.org/processlock.htm
Sometimes, you try to move or delete a file or folder and receive access violation or file in use - errors. To successfully delete a file, you will need to identify the process which has locked the file. You need to exit the process first and then delete the particular file. To know which process has locked a file, you may use one of the methods discussed in this article.
Using Process Explorer - download from http://download.sysinternals.com/files/ProcessExplorer.zip
Process Explorer shows you information about which handles and DLLs processes have opened or loaded.
Download Process Explorer from Microsoft site and run the program.
Click the Find menu, and choose Find Handle or DLL...
Type the file name (name of the file which is locked by some process.)
After typing the search phrase, click the Search button
You should see the list of applications which are accessing the file.
I bumped on the same problem recently. Using PE I'd figured that only process using that particular directory was explorer.exe. I'd opened few windows with explorer, one pointing to parent directory of one that I was about to move.
It appeared, that after I visited that sub-folder and then returned (even to root level!) the handle was still being kept by explorer, so C# was not able to modify it in any way (changing flags, attributes etc.).
I had to kill that explorer window in order to made C# operate properly.
File.SetAttributes(Application.dataPath + "/script", FileAttributes.Normal);
Directory.Move(Application.dataPath + "/script", Application.dataPath + "/../script");
This fixed my problem.
Try this:
If this does not solve, maybe check/change the antivirus, or the some other program is locking some file in or the folder.
static object moveLocker = new object();
static void moveToArchive()
{
lock (moveLocker)
{
System.Threading.Thread.Sleep(2000); // Give sometime to ensure all file are closed.
//Environment.CurrentDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
string applicationPath = System.AppDomain.CurrentDomain.BaseDirectory;
string archiveBaseDirectoryPath = System.IO.Path.Combine(applicationPath, "Archive");
if (!Directory.Exists(archiveBaseDirectoryPath)) Directory.CreateDirectory(archiveBaseDirectoryPath);
String timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
String outputDirectory = System.IO.Path.Combine(Environment.CurrentDirectory, "Output");
String destinationTS = System.IO.Path.Combine(archiveBaseDirectoryPath, timestamp);
try
{
Directory.Move(outputDirectory, destinationTS);
}
catch (Exception ex)
{
Console.WriteLine("Can not move folder " + outputDirectory + " to: " + destinationTS + "\n" + ex.Message);
}
}
}
I had the same problem, it failed sometimes but not all the time. I thought I'd wrap it in a Try Catch block and present the user with an Access Denied message and once I wrapped it in the Try Catch block it stopped failing. I can't explain why.
If existingFile.FileName <> newFileName Then
Dim dir As New IO.DirectoryInfo(existingFile.FilePath)
Dim path As String = System.IO.Path.GetDirectoryName(dir.FullName)
newFileName = path & "\" & newFileName
File.SetAttributes(existingFile.FilePath, FileAttributes.Normal)
Try
IO.File.Move(existingFile.FilePath, newFileName)
Catch ex As Exception
End Try
End If
I had a similar problem. Renamed many directories in a loop when following the certain template. From time to time the program crashed on different directories. It helped to add a sleep thread before Directory.Move. I need to create some delay.
But it slows down the copying process.
foreach (var currentFullDirPath in Directory.GetDirectories(startTargetFullDirectory, "*", SearchOption.AllDirectories))
{
var shortCurrentFolderName = new DirectoryInfo(currentFullDirPath).Name.ToLower();
if (shortCurrentFolderName.Contains(shortSourceDirectoryName))
{
// Add Thread.Sleep(1000);
Thread.Sleep(1000);
var newFullDirName = ...;
Directory.Move(currentFullDirPath, newFullDirName);
}
}

How to properly use File.Exists in windows application

I have a windows application with an "images" folder. I need to check if an image exists, which it will, during runtime. The below code is what I have but it always returns false.
if ( File.Exists("images/" + item.tool_image) )
{
Image img;
img = Image.FromFile("images/" + item.tool_image);
titem.Image = img;
}
Whats the problem or the proper way to do this.
If the file you're looking for doesn't exist in the working directory of your application, call File.Exists with a fully-qualified path:
if (File.Exists(#"C:\images\" + item.tool_image))
{ ... }
Of course, verify that a file actually exists at that location.
You'll find life easier if you use the tools provided by the Path class:
if (File.Exists(Path.Combine(#"C:\images", item.tool_image)))
{ ... }
The path is wrong try to change it to
string basePath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
string imageFileName = System.IO.Path.Combine(basePath, "Images",item.tool_image);
if ( File.Exists(imageFileName) )
{
Image img;
img = Image.FromFile(imageFileName);
titem.Image = img;
}
How to properly use File.Exists in windows application?
You don't!
It's almost never appropriate to check if a file exists before trying to open. There are other things at work here: permissions, locking, sharing, time.
Instead, the correct way to do this is to try to open the file, whether it exists or not, and then catch the exception if your attempt to open the file fails. You have to be able to handle this exception anyway, even after performing the File.Exists() check. This makes your initial File.Exists() check not only redundant to your code, but wasteful, because it causes an extra trip out to the file system... and there's not much you can do in programming that's slower than going to the file system.
it is looking from the location where the code is currently running, also the '/' is the wrong direction. also, you are defining the path in multiple places, which can lead to problems later.
var path = string.Format(#"c:\somewhere\images\{0}", item.tool_image);
if (File.Exists(path))
{
Image img;
img = Image.FromFile(path);
titem.Image = img;
}
it's up to you to set the variable path , but in all likelihood, in your code example the location you expect isn't being checked.
The way you're calling it, you are looking for a file of whatever is in the string item.tool_image inside the images folder. Note that this images folder is located inside whatever directory contains your executable.
For instance, i just called File.Exists("images/image.jpg") and it worked.
As everyone has mentioned, use the fully qualified path. I also make heavy use of the Path.Combine, so I don't have to worry about missing a slash or two when I'm combining directories. The current executing directory is also useful...
File.Exists(Path.Combine(Environment.CurrentDirectory, "Images", item.tool_image));

C# Creating a text file contains the error logs

I have created a text file to save the error in that created file. I have a button which, once pressed, generates an error which should be saved to the file. But if I press the button twice, it will overwrite the first error generated, because the contents of the file are overwritten. I want to generate a another separate file to save the new error. A new file should be generated for each new error.
Thanks in advance
Simple use: FileExists Method and then if it exists pick a new name. Alternatively you could just append to the file.
PSUDO:
public string checkFileName(string fileName){
if(File.Exists(fileName)){
/Pick a new one
newFileName= fileName + DateTime.Now.ToLongDateString()
return checkFileName(newFileName)
}
return fileName
}
This could be the perfect link for you How to Open and Append a log file
You can add time stamp in filename, in this case you would get new file each time.
private void SaveErrorMessage(string errorMessage)
{
string errorFile = null;
for( int x = 0; x < Int32.MaxValue; ++x )
{
errorFile = string.Format(CultureInfo.InvariantCulture, "error-{0}.txt", x);
if( !System.IO.File.Exists(errorFileTest) )
{
break;
}
}
File.WriteAllText(errorFile, errorMessage);
}
This will overwrite the last file after you've had Int32.MaxValue files, but that'll take a while.
An alternative (and probably better) approach would be to simply append to the file, rather than creating a new one.
You may also want to consider using a more robust logging solution, such as log4net.
Creating file in C# is probably what you're looking for.
So you want to generate a unique file name for each error that occurs in your program? Probably the easiest way to accomplish this is to use the date/time when the error occured to name the file. In the function where you are writing to the file you will want to name the file like this:
string filename = LogPath + DateTime.Now.ToString("yyyyMMdd.HHmmss") + ".err";
Where LogPath is the path to the folder you want to write the error files to.

Categories

Resources