I have a program that employs a simple logging process. The idea is that every day a new file gets created that corresponds with the date unless the file already exists, in which case it's just appended to. The problem is, File.Create is throwing an error every time it runs. I found a solution to the problem that says File.Create is opening a FileStream and you just need to call it with a .close(); but that solution didn't work for me, I'm still getting the IO exception saying that the file is in use by another process, which is impossible since it doesn't exist until File.Create creates it, and nothing else uses these files.
Here's the code:
public static void logResults(System.Reflection.MethodBase method, Results result, string message)
{
string date = DateTime.Now.ToString();
int index = date.IndexOf(" ");
string subString = date.Substring(0, index);
string nwDate = Regex.Replace(subString, "/", "");
logFileName = "WebsiteRegressionProduction_TestCycle." + nwDate;
string currentLogFile = logFileLocation + #"\" + logFileName;
StringBuilder sb = new StringBuilder();
if (!File.Exists(currentLogFile))
{
File.Create(currentLogFile).Close();
sb.Append("DATE-TIME\tACTION\tTEST CLASS\tTEST NAME\tTEST STATUS\tERROR MESSAGES");
sb.Append("\n");
}
else
{
string previousLogs = File.ReadAllText(currentLogFile);
sb.Append(previousLogs);
}
sb.Append(DateTime.Now.ToString());
sb.Append(" : ");
sb.Append("Text Executed: ");
sb.Append(method.ReflectedType.Name + " : ");
sb.Append(method + " : ");
sb.Append(result.ToString());
sb.Append(" : ");
sb.Append(message);
sb.Append("\n");
sb.Append("\n");
File.WriteAllText(currentLogFile, sb.ToString());
File.AppendText is probably a much better option for what you are trying to accomplish. It will create the file if it is missing and add the text to the end. If you want to add the header to the start of the file, you'll just have to do a quick manual check to see if the file exists first.
Using suggestions from the answers, I've changed my code. It doesn't throw an exception anymore when first creating the file, but I'll mark an answer as Accepted when someone can explain why File.Create was throwing an IOException saying that the file was already in use and could not be accessed.
public static void logResults(System.Reflection.MethodBase method, Results result, string message)
{
string date = DateTime.Now.ToString();
int index = date.IndexOf(" ");
string subString = date.Substring(0, index);
string nwDate = Regex.Replace(subString, "/", "");
logFileName = "WebsiteRegressionProduction_TestCycle." + nwDate;
string currentLogFile = logFileLocation + #"\" + logFileName;
if (!File.Exists(currentLogFile))
{
File.WriteAllText(currentLogFile,
"DATE-TIME\tACTION\tTEST CLASS\tTEST NAME\tTEST STATUS\tERROR MESSAGES\n\n", Encoding.ASCII);
}
var sb = new StringBuilder();
sb.Append(String.Format("{0} : Test Executed: {1} : {2} : {3}\n\n", DateTime.Now.ToString(),
method.ReflectedType.Name, method, message));
using (var stream = File.AppendText(currentLogFile))
{
stream.Write(sb.ToString());
}
}
1) Why do you read all previous content to append?
2) You can simply use log4net that do all that work for "free"
However, I suggest you to use a stream to have more control over the operation
FileStream fs = new FileStream(filePath, FileMode.Append);
byte[] data = Encoding.ASCII.GetBytes("The string you wanna append");
fs.Write(data, 0, data.Length);
fs.Flush();
fs.Close();
The FileMode.Append open the specified (filePath) in Append if exists or create it if not.
File.Create returns FileStream, so you should be using a FileStream object like so:
FileStream fs = File.Create(currentLogFile);
Then do all your read/writes with the fs object.
Related
This is what I did to create and write on my file:
Create_Directory = #"" + path;
Create_Name = file_name;
private void Create_File(string Create_Directory, string Create_Name )
{
string pathString = Create_Directory;
if (!System.IO.Directory.Exists(pathString)) { System.IO.Directory.CreateDirectory(pathString); }
string fileName = Create_Name + ".txt";
pathString = System.IO.Path.Combine(pathString, fileName);
if (!System.IO.File.Exists(pathString)) { System.IO.File.Create(pathString); }
///ERROR BE HERE:
System.IO.StreamWriter file = new System.IO.StreamWriter(pathString);
file.WriteLine(Some_Method(MP.Mwidth, MP.Mheight, MP.Mtype, "" ));
file.Close();
}
The problem here, which I have battled the entire day, is writing the file after I create it. So, my program creates a file just fine, then gives out an error before writing:
"An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll"
"Additional information: The process cannot access the file 'D:\Projects\Project 15\Project 15\world\world maps\A.txt' because it is being used by another process."
Funny thing though, when I run the program again and try to create an already existing file, as you can see, it skips file creating, goes to writing and works fine, and I would really want my program to create the file and write without having to rerun it... What am I not seeing here?? :S
The problem is that File.Create returns an opened Stream, and you're never closing it. The file is "in use" (by you) at the point in time when you create your StreamWriter.
That being said, you don't need to "create" the file. StreamWriter will automatically do it for you. Just remove this line:
if (!System.IO.File.Exists(pathString)) { System.IO.File.Create(pathString); }
And everything should work as written.
Note that I would rewrite this slightly, however, to make it safer:
private void Create_File(string directory, string filenameWithoutExtension )
{
// You can just call it - it won't matter if it exists
System.IO.Directory.CreateDirectory(directory);
string fileName = filenameWithoutExtension + ".txt";
string pathString = System.IO.Path.Combine(directory, fileName);
using(System.IO.StreamWriter file = new System.IO.StreamWriter(pathString))
{
file.WriteLine(Some_Method(MP.Mwidth, MP.Mheight, MP.Mtype, "" ));
}
}
You can also just use File.WriteAllText or similar methods to avoid creating the file this way. Using the using block guarantees the file will be closed, even if Some_Method raises an exception.
You can use the File class as it wraps up a lot of the work for you
Example:
private void Create_File(string Create_Directory, string Create_Name)
{
string pathString = Create_Directory;
if (!System.IO.Directory.Exists(pathString)) { System.IO.Directory.CreateDirectory(pathString); }
pathString = System.IO.Path.Combine(pathString, Create_Name + ".txt");
File.WriteAllText(fileName, Some_Method(MP.Mwidth, MP.Mheight, MP.Mtype, ""));
}
static void Main(string[] args)
{
FileStream fs = new FileStream("D:\\niit\\deep.docx", FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
sr.BaseStream.Seek(0, SeekOrigin.Begin);
string str = sr.ReadLine();
Console.WriteLine(str);
Console.ReadLine();
}
ok i have solved my problem of finding a unique word within the file that is then used as the newly created .txt file name.
for example: current.txt files have 200 lines of words/data per file but one of the words is unique("92222225") with every current.txt file.
so the newly created output files from streamwriter becomes 92222225.txt, 933333334.txt and so on.
the whole time i though what i needed was within streamreader or streamwriter.
but what i need to add to the two was "Regex.Match".
here is the code i figured out to use for pulling strings out of a .txt file to use as a name for the output files. also to add other words to the new output file.
string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + #"\reporting";
foreach (string txtName in Directory.EnumerateFiles(mydocpath, "*.txt"))
{
StringBuilder sb = new StringBuilder();
StreamReader sr = new StreamReader(txtName);
string content = sr.ReadToEnd();
sb.AppendLine(txtName.ToString());
sb.AppendLine("= = = = = =");
sb.Append(content);
if (content.Contains("helloworld"))
{
sb.AppendLine();
sb.AppendLine("byeworld");
}
sb.AppendLine();
sb.AppendLine();
//string fileName = content.Contains("helloworld").ToString();
string FindMatch = content;
Match match = Regex.Match(FindMatch, #"9(([A-Za-z0-9\-])\d+)");
if (match.Success)
{
//this is what adds unique word as 922225.txt file name.
string capture = match.Groups[1].Captures[0].Value;
using (StreamWriter outfile = new StreamWriter(mydocpath + #"\" + capture + ".txt"))
{
outfile.Write(sb.ToString());
}
}
}
i updated this whole post so if anyone else may need this.
never even used Regex.Match before, nor knew about it or maybe i forgot about it.
If you want to name your output file use:
using (StreamWriter outfile = new StreamWriter(mydocpath + #"\901232lOi.txt"))
This is what I did to create and write on my file:
Create_Directory = #"" + path;
Create_Name = file_name;
private void Create_File(string Create_Directory, string Create_Name )
{
string pathString = Create_Directory;
if (!System.IO.Directory.Exists(pathString)) { System.IO.Directory.CreateDirectory(pathString); }
string fileName = Create_Name + ".txt";
pathString = System.IO.Path.Combine(pathString, fileName);
if (!System.IO.File.Exists(pathString)) { System.IO.File.Create(pathString); }
///ERROR BE HERE:
System.IO.StreamWriter file = new System.IO.StreamWriter(pathString);
file.WriteLine(Some_Method(MP.Mwidth, MP.Mheight, MP.Mtype, "" ));
file.Close();
}
The problem here, which I have battled the entire day, is writing the file after I create it. So, my program creates a file just fine, then gives out an error before writing:
"An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll"
"Additional information: The process cannot access the file 'D:\Projects\Project 15\Project 15\world\world maps\A.txt' because it is being used by another process."
Funny thing though, when I run the program again and try to create an already existing file, as you can see, it skips file creating, goes to writing and works fine, and I would really want my program to create the file and write without having to rerun it... What am I not seeing here?? :S
The problem is that File.Create returns an opened Stream, and you're never closing it. The file is "in use" (by you) at the point in time when you create your StreamWriter.
That being said, you don't need to "create" the file. StreamWriter will automatically do it for you. Just remove this line:
if (!System.IO.File.Exists(pathString)) { System.IO.File.Create(pathString); }
And everything should work as written.
Note that I would rewrite this slightly, however, to make it safer:
private void Create_File(string directory, string filenameWithoutExtension )
{
// You can just call it - it won't matter if it exists
System.IO.Directory.CreateDirectory(directory);
string fileName = filenameWithoutExtension + ".txt";
string pathString = System.IO.Path.Combine(directory, fileName);
using(System.IO.StreamWriter file = new System.IO.StreamWriter(pathString))
{
file.WriteLine(Some_Method(MP.Mwidth, MP.Mheight, MP.Mtype, "" ));
}
}
You can also just use File.WriteAllText or similar methods to avoid creating the file this way. Using the using block guarantees the file will be closed, even if Some_Method raises an exception.
You can use the File class as it wraps up a lot of the work for you
Example:
private void Create_File(string Create_Directory, string Create_Name)
{
string pathString = Create_Directory;
if (!System.IO.Directory.Exists(pathString)) { System.IO.Directory.CreateDirectory(pathString); }
pathString = System.IO.Path.Combine(pathString, Create_Name + ".txt");
File.WriteAllText(fileName, Some_Method(MP.Mwidth, MP.Mheight, MP.Mtype, ""));
}
static void Main(string[] args)
{
FileStream fs = new FileStream("D:\\niit\\deep.docx", FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
sr.BaseStream.Seek(0, SeekOrigin.Begin);
string str = sr.ReadLine();
Console.WriteLine(str);
Console.ReadLine();
}
I am trying to remove the space at the end of line and then that line will be written in another file.
But when the program reaches to FileWriter then it gives me the following error
Process can't be accessed because it is being used by another process.
The Code is as below.
private void FrmCounter_Load(object sender, EventArgs e)
{
string[] filePaths = Directory.GetFiles(#"D:\abc", "*.txt", SearchOption.AllDirectories);
string activeDir = #"D:\dest";
System.IO.StreamWriter fw;
string result;
foreach (string file in filePaths)
{
result = Path.GetFileName(file);
System.IO.StreamReader f = new StreamReader(file);
string newFileName = result;
// Combine the new file name with the path
string newPath = System.IO.Path.Combine(activeDir, newFileName);
File.Create(newPath);
fw = new StreamWriter(newPath);
int counter = 0;
int spaceAtEnd = 0;
string line;
// Read the file and display it line by line.
while ((line = f.ReadLine()) != null)
{
if (line.EndsWith(" "))
{
spaceAtEnd++;
line = line.Substring(0, line.Length - 1);
}
fw.WriteLine(line);
fw.Flush();
counter++;
}
MessageBox.Show("File Name : " + result);
MessageBox.Show("Total Space at end : " + spaceAtEnd.ToString());
f.Close();
fw.Close();
}
}
File.Create itself returns a stream.
Use that stream to write file. Reason you are receiving this error is because Stream returned by File.Create is open and you are trying to open that file again for write.
Either close the stream returned by File.Create or better use that stream for file write or use
Stream newFile = File.Create(newPath);
fw = new StreamWriter(newFile);
Even though you solved your initial problem, if you want to write everything into a new file in the original location, you can try to read all of the data into an array and close the original StreamReader. Performance note: If your file is sufficiently large though, this option is not going to be the best for performance.
And you don't need File.Create as the StreamWriter will create a file if it doesn't exist, or overwrite it by default or if you specify the append parameter as false.
result = Path.GetFileName(file);
String[] f = File.ReadAllLines(file); // major change here...
// now f is an array containing all lines
// instead of a stream reader
using(var fw = new StreamWriter(result, false))
{
int counter = f.Length; // you aren't using counter anywhere, so I don't know if
// it is needed, but now you can just access the `Length`
// property of the array and get the length without a
// counter
int spaceAtEnd = 0;
// Read the file and display it line by line.
foreach (var item in f)
{
var line = item;
if (line.EndsWith(" "))
{
spaceAtEnd++;
line = line.Substring(0, line.Length - 1);
}
fw.WriteLine(line);
fw.Flush();
}
}
MessageBox.Show("File Name : " + result);
MessageBox.Show("Total Space at end : " + spaceAtEnd.ToString());
Also, you will not remove multiple spaces from the end of the line using this method. If you need to do that, consider replacing line = line.Substring(0, line.Length - 1); with line = line.TrimEnd(' ');
You have to close any files you are reading before you attempt to write to them in your case.
Write stream in using statement like:
using (System.IO.StreamReader f = new StreamReader(file))
{
//your code goes here
}
EDIT:
Zafar is correct, however, maybe this will clear things up.
Because File.Create returns a stream.. that stream has opened your destination file. This will make things clearer:
File.Create(newPath).Close();
Using the above line, makes it work, however, I would suggest re-writing that properly. This is just for illustrative purposes.
I'm trying to read from a binary file with BinaryReader.
This is how I call my reading method :
foreach (Movie film in TreeBuilder.myMovies)
{
if (File.Exists(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + film.MovieName + ".txt"))
{
string[] myArray = operationManager.BinaryReading(film.MovieName);
if (myArray != null)
{
this.textStarring.Text = myArray[1];
this.textProduced.Text = myArray[2];
this.textMusic.Text = myArray[3];
this.textYear.Text = myArray[4];
this.textTime.Text = myArray[5];
}
else
{
MessageBox.Show("An error occured");
}
}
This is my reading method :
public string[] BinaryReading(string name)
{
FileStream myStream = new FileStream(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + name + ".txt", FileMode.Open);
BinaryReader reader = new BinaryReader(myStream);
string loadString = reader.ReadString();
string[] loadArray = loadString.Split(',');
reader.Close();
myStream.Close();
return loadArray;
}
Now something within these lines is not working. My file is not empty because since it's only a string I can read whats in the file.
My problem is I'm trying to find whats wrong with a break point but as soon as I get past this line :
string loadString = reader.ReadString();
My program starts to run again. How is that possible ? This prevents me from checking what's inside my String[] and what are my values after the method call.
Any idea why ? Thanks in advance.
Update :
I tried to move my breakpoint here
string[] loadArray = loadString.Split(',');
But my program never stops so it never gets past the previous line.
Also this is my Writting method :
foreach (Movie film in TreeBuilder.myMovies)
{
if (film.MovieName == name)
{
FileStream myStream = new FileStream(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + film.MovieName + ".txt", FileMode.Create);
BinaryWriter writer = new BinaryWriter(myStream);
writer.Write(film.MovieName + "," + starring + "," + produced + "," + music + "," + year + "," + lenght);
writer.Close();
myStream.Close();
}
}
Your string will be prefixed with a length field. That makes the .txt extension misleading.
Since it 'suddenly started working again' : is it possible you opened (and saved) one of the files with a Text editor?
Also, your current Read and Write methods are not thread-safe, you should enclose the Stream and Reader/Writer objects in using() {} statements.