C# open file exception - c#

i have a C# form having troubles with file operations.
Here's how it works :
When the user click on the "start" button, the program begins.
It opens the file (if exists?), check the header of this file and modify a boolean if this header exists.
Then, it opens the file again, to put a header (if non exists) and other infos, or just infos (if header exists)
Here's the code :
public bool enteteExiste = false;
private void start_Click(object sender, EventArgs e)
{
try
{
verifieEntete();
//INSERTION DE L'ENTETE DU FICHIER CSV
writeToCsv = new StreamWriter(boxFilePath.Text + "\\" + filename, true);
canAcces = true;
}
catch (Exception)
{
MessageBox.Show("Droits d'accès au dossier insuffisant OU fichier déjà ouvert" + Environment.NewLine + "Assurez vous d'avoir fermé le fichier et de disposer des droits requis" + Environment.NewLine + "Arrêt de la procédure");
}
}
public void verifieEntete()
{
string absolutFilePath = boxFilePath.Text + '\\' + filename;
String[] fileContent = File.ReadAllText(absolutFilePath).Split(',');
for (int i = 0; i < fileContent.Length; i++)
if (fileContent[i].Contains("MAC;SERIAL;IP;MODELE;MODULE-EXT"))
enteteExiste = true ;
}
When file already exists, program runs perfectly,
When file does not exists, program goes into catch Exception.
Is ReadAllTest() not supposed to check wether file exists or not ?
Should i add a special Exception catch "filenotfound", and create it ?

The MSDN docs for File.ReadAllText state explicitly that it will throw a FileNotFoundException if the file doesn't exist. So yes, you have to explicitly check for its existence.
It's best not to rely on Exceptions for something that can easily be checked beforehand. Both because of potential performance issues (catching an exception is a lot slower than a simple if test), and both for code clarity and readability - an if/else branching is usually easier to understand and structure than a try/catch block. This way you can handle the error before it happens, and fix it (like, say, creating the file if necessary)
public void verifieEntete()
{
string absolutFilePath = boxFilePath.Text + '\\' + filename;
if (!File.Exists(absolutFilePath) // <--- ADD EXPLICIT CHECK
{
// Create the file here.
}
// Now we know the file is *sure* to exist, because we handled it
// explicitly.
String[] fileContent = File.ReadAllText(absolutFilePath).Split(',');
for (int i = 0; i < fileContent.Length; i++)
if (fileContent[i].Contains("MAC;SERIAL;IP;MODELE;MODULE-EXT"))
enteteExiste = true ;
}

Related

File Copy failing to create files with same name

I am copying files from one location to another. I encountered an issue where sometimes a file with the same name would try to save and it would break the program. So I added the logic below to add a number to the filename before copying it:
int counter = 0;
try
{
File.Copy(FileToCopy, FileToSave);
}
catch (Exception)
{
string CurrentFileName = FileToSave.Split('\\', '\\')[4];
string CurretFilePrefix = CurrentFileName.Split('.')[0];
string CurrentFileSuffix = CurrentFileName.Split('.')[1];
string UpdatedFileName = CurretFilePrefix + "_" + counter + "." + CurrentFileSuffix;
File.Copy(FileToCopy, UpdatedFileName);
counter++;
}
However, this is now causing a crash saying the file already exists:
When I check the file does not exist:
Why am I getting this exception? How do I save copies of these files?
A good approach to this problem would include (i) a loop; (ii) use of Path expressions; (iii) avoidance of try-catch when you can test if the file exists; (iv) use of a specific Exception for the extremely unlikely case that two threads or processes are trying to do this same copy at the same time and each get past the File.Exists check; (v) avoidance of while-true-forever loops as even the best code can contain mistakes that could cause a spin-wait forever in production code on a server and it's better to instead have an exception that tells you when something has gone wrong.
int counter = 0;
string proposedDest = dest;
while(counter < 5000)
{
if (!File.Exists(proposedDest))
{
try
{
File.Copy(fileToCopy, proposedDest);
break;
}
catch (IOException ex) when ((uint)ex.HResult == 0x80070050)
{
}
}
counter++;
proposedDest = Path.Combine(Path.GetDirectoryName(dest),
Path.GetFileNameWithoutExtension(dest) +
"_" + counter + Path.GetExtension(dest));
}
;
if (counter == 5000)
throw new Exception($"Could not copy file {fileToCopy} too many retries");
[A better approach would also not use hard coded constants littered through the code ;)]
As CurrentFileName is relative, you are trying to save the file in the location of your executable. Check that directory if your file exists.
Also, there are much better ways to find if the file exists, and also to get the filename and extension of a given file.
i.e. you should use the File.Exists method to determine if the file exists, instead of using exceptions for flow control
if (File.Exists(FileToSave))
{
FileToSave = GetNewFileName(FileToSave)
}
try
{
File.Copy(FileToCopy, FileToSave);
}
catch (Exception)
{
//something went really wrong
}
You should also use the Path methods for getting parts of the name, instead of "knowing" to get the fifth part of the filename (Path.GetExtension, Path.GetFileNameWithoutExtension)
private string GetNewFileName(string oldFileName){
var counter = 0;
var extension = Path.GetExtension(oldFileName);
var directory = Path.GetDirectoryName(oldFileName);
var fileName = Path.GetFileNameWithoutExtension(oldFileName);
var newFileName = Path.Combine(directory,
string.Format("{1}_{2}{3}", filename, counter, extension);
while (File.Exists(newFileName)){
counter++;
newFileName = Path.Combine(directory,
string.Format("{1}_{2}{3}", filename, counter, extension);
}
return newFileName;
}
use this instead:
string CurrentFileName = System.IO.Path.GetFileName(FileToSave);
string CurretFilePrefix = System.IO.Path.GetFileNameWithoutExtension(FileToSave);
string CurrentFileSuffix = System.IO.Path.GetExtension(FileToSave);
string UpdatedFileName = CurretFilePrefix + "_" + counter + "." + CurrentFileSuffix;
Then you have
File.Copy(FileToCopy, UpdatedFileName);
Are you sure this shouldn't be
File.Copy(FileToSave, UpdatedFileName); // FileToSave instead of FileToCopy

Save and delete Excel file saved using HttpPostedFileBase

I am uploading an Excel file and extracting data from that and saving it into a database. I am using MVC4 .NET Framework. This is my code from class:
public static void Upload(HttpPostedFileBase File)
{
NIKEntities1 obj = new NIKEntities1();
MyApp = new Excel.Application();
MyApp.Visible = false;
string extension = System.IO.Path.GetExtension(File.FileName);
string pic = "Excel" + extension;
string path = System.IO.Path.Combine(System.Web.HttpContext.Current.Server.MapPath("~/Excel"), pic);
File.SaveAs(path);
MyBook = MyApp.Workbooks.Open(path);
MySheet = (Excel.Worksheet)MyBook.Sheets[1]; // Explicit cast is not required here
int lastRow = MySheet.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell).Row;
List<Employee> EmpList = new List<Employee>();
for (int index = 2; index <= lastRow; index++)
{
System.Array MyValues = (System.Array)MySheet.get_Range("A" +
index.ToString(), "B" + index.ToString()).Cells.Value;
EmpList.Add(new Employee
{
BatchID = MyValues.GetValue(1, 1).ToString(),
BatchName = MyValues.GetValue(1, 2).ToString()
});
}
for (int i = 0; i < EmpList.Count; i++)
{
int x=obj.USP_InsertBatches(EmpList[i].BatchID, EmpList[i].BatchName);
}
}
}
class Employee
{
public string BatchID;
public string BatchName;
}
This code is working perfectly the first time but next time it says that file is currently in use. So I thought of deleting the file at the end of code using the following line:
File.Delete(path);
But this line threw error:
HttpPostedFileBase does not contain definition for Delete
Also, if I don't write this line and try to execute code again it says that it can't save because a file exists with same name and could not be replaced because it is currently in use.
What should I do to get rid of this:
(File.Delete()) Error
Any other way of accessing the Excel file which I am receiving without saving will also be very helpful because I have to just access the data one time.
The File you use there is your variable that is the input parameter of your method. That parameter is of type HttpPostedFileBase and that type has no instance methods (nor static ones for that matter) that allow you to delete that File instance.
You are probably looking for the static Delete method on the File type that is in the System.IO namespace.
A quickfix would be to be explicit about which File you mean:
System.IO.File.Delete(path);
You might want to consider a different naming guideline for your variables though. In c# we tend to write variables starting with a lower case letter. Almost all types in the framework start with an Uppercase letter. Which makes it easier to distinguish the thing file and the type File.
Do notice that a file can only be deleted if it is closed by all processes and all file handles are cleared by the filesystem. In your case you have to make sure Excel closed the file and released it's handles. If you have the search indexer running or a rough virus scanner you might have to try a few times before giving up.
I normally use this code:
// make sure here all Ole Automation servers (like Excel or Word)
// have closed the file (so close the workbook, document etc)
// we iterate a couple of times (10 in this case)
for(int i=0; i< 10; i++)
{
try
{
System.IO.File.Delete(path);
break;
} catch (Exception exc)
{
Trace.WriteLine("failed delete {0}", exc.Message);
// let other threads do some work first
// http://blogs.msmvps.com/peterritchie/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program/
Thread.Sleep(0);
}
}
From what I can tell, you are opening Excel, reading the file but never closing the Excel.
Add:
MyApp.Workbooks.Close();
MyApp.Quit();
at the end of the Upload function. Even better, wrap whole code you got in
try{
//here goes your current code
}
catch(Exception e)
{
//manage exception
}
finally
{
MyApp.Workbooks.Close();
MyApp.Quit();
}
You initialize MyApp outside try catch block, then whatever happens close the file.

Error on FileCopy when there are white spaces in path and name

I've seen some questions regarding this topic, but none of them solved the problem completely.
I want to copy some files, overwriting if the name already exists. The function File.Copy(source, destination,true) works perfectly if the destination file does not exists, and also if the original file has no withespaces in its path.
BUT when there are whitespaces, I get an "Access denied" error. I have permissions in both paths, and the rest of the files are correctly overwritten.
Tried with "#" literal with no luck, also quoting both paths (got an ArgumentException in this case).
Here is my code:
private void button1_Click(object sender, EventArgs e)
{
int totalPaths = pathList.Count;
int totalCorrectPaths = 0;
string currentFile = "";
string failedFiles = "";
string destination = "";
bool errors=false;
for (int i = 0; i < totalPaths; i++)
{
progressBar1.Value = Convert.ToInt16((100.0 * i) / totalPaths);
listBox1.SelectedIndex = i;
//currentFile = (String) listBox1.SelectedValue;
currentFile = pathList.ElementAt(i);
try
{
destination=Path.Combine(textBox2.Text,Path.GetFileName(currentFile));
File.Copy(currentFile,destination, true);
totalCorrectPaths++;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\nCopiando el archivo:\n" + currentFile, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
errors = true;
failedFiles+="\n"+ex.Message+" "+currentFile;
}
}
if (errors)
{
MessageBox.Show(totalCorrectPaths +" canciones se han copiado correctamente"+"\nErrores al copiar los siguientes archivos:\n" + failedFiles, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else {
MessageBox.Show(totalCorrectPaths +" canciones se han copiado correctamente", "Finalizado", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
Any hint will be very appreciated.
UPDATE 3: Definitely not a permission issue on source folder, as rest of the files got succesfully copied. Running as admin did not improve it.
Maybe you are right and I am pointing in the wrong direction, but I can't figure what's wrong. Here is an image with some of the names that throw errors (with my current test they are 20 out of 820 files). Sorry about screenshot in spanish, each line is composed of "destination" "UnauthorizedAccessException.Message" "source".
Screenshot link: http://i.imgur.com/texV67H.png
UPDATE 4: As some of you pointed, i was wrong, as the example suggested by #sstan works, still can't figure what do the failing files have in common
static void Main(string[] args)
{
string source = Path.GetFullPath(#"C:\test this\hello 1.txt");
string destination = Path.GetFullPath(#"C:\test this\hello 2.txt");
File.Copy(source, destination, true);
}
UPDATE 5: The code above works, the following one reproduces the fail (first execution works, 2nd and following fail due to the file already present)
static void Main(string[] args)
{
string source = Path.GetFullPath(#"C:\test this\01 Test.mp3");
string destination = Path.GetFullPath(#"C:\test this\01 Test copy.mp3");
File.Copy(source, destination, true);
}
Finally found the problem: the readonly attribute.
Most of the comments were right, finally it wasn't related to whitespaces despite i pointed to it seeing the errors, it was just a coincidence with some of the first items of the list.
As I stated in the comments, found the problem thanks to ssatan suggestion about the problem being format related. I copied some of the faulty files to other folder, and got failed copys despite removing all the whitespaces. After that i made an empty mp3 file with the same name as the original, it worked like a charm.
Seems obvious now, the copied file carries the readonly attribute with him. It's ignored if i copy it manually, but the File.Copy() function checks it and throws an UnauthorizedAccessException (as it should).

Trouble Moving files in C#?

I am making a software that will move files from the downloads folder to a specific sub folder in a directory. The sub folder is selected by the user by a combobox. I keep getting this error: System.IO.IOException: Cannot create a file when that file already exists. Also, these error come up on people's computer who install my program...exceptions and things. How do i turn it off. Also, why do i get this error? Here is my code:
string pathUser4 = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string pathDownload4 = (pathUser4 + #"\Downloads\");
string sourceFile = pathDownload4 + listBox1.Text;
string pathdoc5 = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string pathDownload5 = (pathdoc5 + #"\iracing\setups\");
string destinationFile = pathDownload5 + comboBox1.Text;
File.Move(sourceFile, destinationFile);
if (comboBox1.Text == "Select File Destination")
{
MessageBox.Show("Please Select A Destination Folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Each File.Move should be wrapped in a try/catch block as you can never expect an IO operation to execute without error. It could be something as simple as the user having a file handle open, or the file existing in the destination folder, either way, you don't want a single file to throw an exception that stops the entire operation. You will want to catch the exceptions and log them either to an error log file or to the event log, this way you can see the errors that occurred but it will not interrupt anything.
Secondly, for any desktop application I would add global error handling to log any uncaught errors. You can do this by putting this code at the beginning of your program,
AppDomain.CurrentDomain.UnhandledException += (a, exception) => File.AppendAllText("errorlog.txt", exception.ToString() + "\n"
This will keep the user from ever seeing ugly exceptions being thrown. Also be sure you are not giving the users the .pdb files as this will cause exceptions to contain paths of the computer it was compiled on which can contain your username and other sensitive information you wouldn't want a client to see.
You can register the global exception handling when the main window is initialized, you want it to be the first thing you do before any thing else because again you never know when an exception will be thrown so you have to think defensively.
public partial class MainWindow : Window
{
public MainWindow()
{
AppDomain.CurrentDomain.UnhandledException += (a, exception) => File.AppendAllText("errorlog.txt", exception.ToString() + "\n");
InitializeComponent();
}
}
C# uses exceptions extensively so it will be good concept for you to study up on if you are not familiar with this type of error handling. All exceptions derive from the Exception class so when you write catch (Exception e) this will catch all exceptions (because a base reference can hold an object of a derived type), however if you know the specific exception a method will throw you can catch a more specific exception (always before the more general catch) and handle it in a specific way. In this example you may have an IOException from the File.Move() that you want to catch and handle differently.
try
{
string pathUser4 = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string pathDownload4 = (pathUser4 + #"\Downloads\");
string sourceFile = pathDownload4 + listBox1.Text;
string pathdoc5 = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string pathDownload5 = (pathdoc5 + #"\iracing\setups\");
string destinationFile = pathDownload5 + comboBox1.Text;
File.Move(sourceFile, destinationFile);
if (comboBox1.Text == "Select File Destination")
{
MessageBox.Show("Please Select A Destination Folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception e)
{
File.AppendAllText("ErrorLog.txt", e.ToString() + "\n");
}
The example code from MSDN for File.Move should get you pointed at the various things you need to deal with, such as an already existing file and basic error handling.
using System;
using System.IO;
class Test
{
public static void Main()
{
string path = #"c:\temp\MyTest.txt";
string path2 = #"c:\temp2\MyTest.txt";
try
{
if (!File.Exists(path))
{
// This statement ensures that the file is created,
// but the handle is not kept.
using (FileStream fs = File.Create(path)) {}
}
// Ensure that the target does not exist.
if (File.Exists(path2))
File.Delete(path2);
// Move the file.
File.Move(path, path2);
Console.WriteLine("{0} was moved to {1}.", path, path2);
// See if the original exists now.
if (File.Exists(path))
{
Console.WriteLine("The original file still exists, which is unexpected.");
}
else
{
Console.WriteLine("The original file no longer exists, which is expected.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
}
The error may caused by your code, or by some invalid input.
As #Despertar mentioned, I suggest all the program include error handling and log features in your code. It will be very helpful for your debug.
But I suggest use open source log library, not do it by yourself. For example, log4net, NLog, etc.

Writing to a text file on form closing event

I am trying to write some strings to a text file on the formclosing event. The problem is that the streamwriter doesn't write anything, it just writes a blank slate. I have 2 different text files, the first one will log all of the graph data and the second text file will log a couple of preferences relevant to my application. My code is shown below for both the closing event and a seperate workhorse method:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason.Equals(CloseReason.WindowsShutDown) || (e.CloseReason.Equals(CloseReason.UserClosing)))
{
if (MessageBox.Show("You are closing this application.\n\nAre you sure you wish to exit ?", "Warning: Not Submitted", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Stop) == DialogResult.Yes)
{
writeContents("Interrupted");
return;
}
else
e.Cancel = true;
}
}
private void writeContents(string status)
{
//---writes the graph data-----
TextWriter twBackupData = new StreamWriter("C://springTestBackupData.txt");
twBackupData.WriteLine("--Cycle#-- --TorqueLower-- --TorqueUpper--");
//writes the table of values in there, assume x and y are the same size arrays
for(int i = 0; i < x.Count; i++)
{
twBackupData.WriteLine(x[i] + " " + y_lower[i] + " " + y_upper[i]);
}
//---writes some of the preferences------
TextWriter twBackupDataInfo = new StreamWriter("C://springTestBackupInfo.txt");
twBackupDataInfo.WriteLine(status);
twBackupDataInfo.WriteLine(cycleCount.ToString());
twBackupDataInfo.WriteLine(section.ToString());
twBackupDataInfo.WriteLine(revsPerCycle.ToString());
twBackupDataInfo.WriteLine(preturns.ToString());
twBackupDataInfo.WriteLine(direction.ToString());
}
If you can provide advice or help me find out why it's writing blanks I would greatly appreciate it. Thank you!
You need to close the StreamWriter using the using statement.
It's much easier to just use:
var linesToWrite = new list<string>();
linesToWrite.Add(status);
linesToWrite.Add(cycleCount.ToString());
...
File.WriteAllLines("C://springTestBackupData.txt", linesToWrite);
You need to close/dispose the writer for it to write, otherwise it never flushes its stream (i.e. writes the data to the file)
Using the 'using' statement automatically disposes of an object when it goes out of scope so:
using(TextWriter twBackupData = new StreamWriter("C://springTestBackupData.txt"))
{
// Do your stuff here - write to the tw ---
twBackupData.WriteLine("--Cycle#-- --TorqueLower-- --TorqueUpper--");
//writes the table of values in there, assume x and y are the same size arrays
for(int i = 0; i < x.Count; i++)
{
twBackupData.WriteLine(x[i] + " " + y_lower[i] + " " + y_upper[i]);
}
}
Will ensure your file gets written to
More info here:
http://msdn.microsoft.com/en-us/library/yh598w02.aspx
You need to do .Close() on your StreamWriters;

Categories

Resources