I'm playing around with C# and I encountered a problem.
When I try to make a new file, the program breaks and says that the file is being used by another process. It's probably something stupid that I overlooked, but I cant figure it out!
Here is my code:
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace myNameSpace
{
public partial class MainWindow : Form
{
public static string folderPath = #"fullpath";
public MainWindow()
{
InitializeComponent();
StoredTb.Text = folderPath;
String[] files = Directory.GetFiles(folderPath);
foreach (string file in files)
myDropDown.Items.Add(Path.GetFileNameWithoutExtension(file));
}
private void myDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
this.BeginInvoke(new MethodInvoker(myDropDown_invokedMethod));
}
private void myDropDown_invokedMethod()
{
string fullpath = MainWindow.folderPath + myDropDown.SelectedText + ".txt";
StreamReader sr = new StreamReader(fullpath);
NameTb.Text = myDropDown.SelectedText;
DescriptionTb.Text = sr.ReadToEnd();
sr.Close();
}
private void SaveBtn_Click(object sender, EventArgs e)
{
File.Create(NameTb.Text + ".txt");
TextWriter tw = new StreamWriter(NameTb.Text + ".txt"); /* this is where the problem occurs */
tw.WriteLine("The very first line!");
tw.Close();
}
}
}
Sorry for the long code snippet, but since I'm not sure where the problem originates from I had to include pretty much everything.
Your problem is that File.Create will open a stream allowing you to do what you like to the file:
http://msdn.microsoft.com/en-us/library/d62kzs03.aspx
A FileStream that provides read/write access to the file specified in path.
Therefore, technically, it is in use already.
Just remove the File.Create altogether. The StreamWriter will handle creating the file if it doesn't exist.
Also, invest in using constructs to properly dispose of your file connections too. Will help avoid this in the future.
As per MSDN the File.Create Method (String) uses a FileStream which in your case is not being closed. Use something like this:
FileStream fs = new FileStream(NameTb.Text + ".txt");
File.Create(fs);
fs.Close();
or #Muctadir Dinar
var fileStream = File.Create(NameTb.Text + ".txt");
//... do all the writing using fileStream
fileStream.Close();
Use
myDropDown_invokedMethod();
instead of
this.BeginInvoke(new MethodInvoker(myDropDown_invokedMethod));
File.Create returns a FileStream object which holds your file. You should use this object for further task.
var fileStream = File.Create(NameTb.Text + ".txt");
//... do all the writing using fileStream
fileStream.Close();
or you could do just
var fs = File.Create(NameTb.Text + ".txt");
fs.Close();
TextWriter tw = new StreamWriter(NameTb.Text + ".txt");
tw.WriteLine("The very first line!");
tw.Close();
Your problem seems to be in SaveBtn_Click event, you are using your destination file twice for writing:
File.Create(NameTb.Text + ".txt");
TextWriter tw = new StreamWriter(NameTb.Text + ".txt");
Remove this line:
File.Create(NameTb.Text + ".txt");
Thats because the File.Create(NameTb.Text + ".txt"); keeps the file open:
try use this instead:
private void SaveBtn_Click(object sender, EventArgs e)
{
using(Stream stream = File.Create(NameTb.Text + ".txt"))
{
TextWriter tw = new StreamWriter(stream); /* this is where the problem was */
tw.WriteLine("The very first line!");
tw.Close();
}
}
This wil force the File.Create to be Disposed when the method has exits. The dispose will close the filehandle (win32 unmanaged handle). Otherwise the file will be closed by the garbage collector, but you never know when.
I see 2 ways:
1)use System.IO.File.WriteAllText http://msdn.microsoft.com/en-us/library/vstudio/8bh11f1k.aspx
2)read about disposing http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
Related
I'm trying to read and write to the same file in a way such that no other program can access the file in between:
FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
StreamReader sr = new StreamReader(fs);
StreamWriter sw = new StreamWriter(fs);
newString = sr.ReadToEnd() + "somethingNew";
sw.Write(newString);
fs.Close();
The file is never written to. If I debug I can see that the reader manages to fetch the contents of the file, but the writer does not seem to be able to write to the file. Nothing happens.
I've been looking at this question which seems to be the same as mine. However I'm not able to get it to work.
Just Flush your changes to file, Have sw.Flush(); before closing the stream. like:
string filePath = "test.txt";
FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
StreamReader sr = new StreamReader(fs);
StreamWriter sw = new StreamWriter(fs);
newString = sr.ReadToEnd() + "somethingNew";
sw.Write(newString);
sw.Flush(); //HERE
fs.Close();
You may see this post simultaneous read-write a file in C# (open multiple streams for reading and writing)
As mentioned above - just add the Flush() to force the data held in the stream to be written to the file. In a comment you mentioned that you had previously used a 'using' statement but this hadn't worked.
Briefly here's why:
A using statement automatically calls Flush() so you don't have
to.
When you dispose of a StreamReader (or StreamWriter) - like by using a 'using' statement - the inner stream object is also disposed and you lose the handle to the stream.
#EJS a simple static method that you can use to create a new file if it does not exist as well as write to the same file if it does exist
Simple usage
string path = #"C:\SomePath\Name.txt";
if (!System.IO.File.Exists(path))
{
WriteAndOrAppendText(path, "File Created");
}
else if (System.IO.File.Exists(path))
{
WriteAndOrAppendText(path, "New Boot.");
}
private static void WriteAndOrAppendText(string path, string strText)
{
if (!File.Exists(path))
{
using (StreamWriter fileStream = new StreamWriter(path, true))
{
fileStream.WriteLine(strText);
fileStream.Flush();
fileStream.Close();
}
}
else
{
using (StreamWriter fileStream2 = new StreamWriter(path, true))
{
fileStream2.WriteLine(strText);
fileStream2.Flush();
fileStream2.Close();
}
}
}
For being able to create a file, append to it, and read the data in it while still allowing an application to write to it, as I believe you are trying to do, here's a set up I created:
string path = #"C:\SomePath\MyLogFile.txt";
public static string Log(string Message)
{
try
{
if (File.Exists(path) == false)
File.Create(path).Close(); // need this .Close()!!!
logCounter++;
string logString = logCounter + " " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + ": " + Message + Environment.NewLine;
using (FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(logString);
}
}
return logString; // only necessary so we can return an error in the Exception block
}
catch (Exception ex)
{
return "Logger: Cannot log data. " + ex.ToString();
}
}
It's actually required to use FileAccess.Write if you do FileMode.Append - instead of being able to use FileAccess.ReadWrite - but I found that didn't matter because whatever had been written would have been closed and flushed to the file, and I could still open the file and read it (it wouldn't be locked & blank) using these. I have sw.Write() because I have Environment.NewLine that I added into my logString, but I could've done sw.WriteLine() and removed that, if I had wanted to.
One caveat: File.Exists() has issues if the path is long - can't remember the limit, but just know that there is one, so don't put your file you're writing to several layers deep. Less is always better.
This piece of code worked perfectly in VS 2010. Now that I have VS 2013 it no longer writes to the file. It doesn't error or anything. (I get an alert in Notepad++ stating that the file has been updated, but there is nothing written.)
It all looks fine to me. Any Ideas?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
String line;
try
{
//Pass the file path and file name to the StreamReader constructor
StreamReader sr = new StreamReader("C:\\Temp1\\test1.txt");
StreamWriter sw = new StreamWriter("C:\\Temp2\\test2.txt");
//Read the first line of text
line = sr.ReadLine();
//Continue to read until you reach end of file
while (line != null)
{
//write the line to console window
Console.WriteLine(line);
int myVal = 3;
for (int i = 0; i < myVal; i++)
{
Console.WriteLine(line);
sw.WriteLine(line);
}
//Write to the other file
sw.WriteLine(line);
//Read the next line
line = sr.ReadLine();
}
//close the file
sr.Close();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
finally
{
Console.WriteLine("Executing finally block.");
}
}
}
}
You need to close StreamWriter. Like this:
using(var sr = new StreamReader("..."))
using(var sw = new StreamWriter("..."))
{
...
}
This will close streams even if exception is thrown.
You need to Flush() the StreamWriter after write.
By default StreamWriter is buffered that means it won't output until it receives a Flush() or Close() call.
Also you can also try to close it like this:
sw.Close(); //or tw.Flush();
You can also have a look at StreamWriter.AutoFlush Property
Gets or sets a value indicating whether the StreamWriter will flush
its buffer to the underlying stream after every call to
StreamWriter.Write.
The other option which is now a days very popular and recommended is to use the using statement which takes care of it.
Provides a convenient syntax that ensures the correct use of
IDisposable objects.
Example:
using(var sr = new StreamReader("C:\\Temp1\\test1.txt"))
using(var sw = new StreamWriter("C:\\Temp2\\test2.txt"))
{
...
}
using System.IO;
class test
{
public static void Main()
{
string path=#"c:\mytext.txt";
if(File.Exists(path))
{
File.Delete(path);
}
FileStream fs=new FileStream(path,FileMode.OpenOrCreate);
StreamWriter str=new StreamWriter(fs);
str.BaseStream.Seek(0,SeekOrigin.End);
str.Write("mytext.txt.........................");
str.WriteLine(DateTime.Now.ToLongTimeString()+" "+DateTime.Now.ToLongDateString());
string addtext="this line is added"+Environment.NewLine;
File.AppendAllText(path,addtext); //Exception occurrs ??????????
string readtext=File.ReadAllText(path);
Console.WriteLine(readtext);
str.Flush();
str.Close();
Console.ReadKey();
//System.IO.IOException: The process cannot access the file 'c:\mytext.txt' because it is //being used by another process.
// at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
}
}
Try This
string path = #"c:\mytext.txt";
if (File.Exists(path))
{
File.Delete(path);
}
{ // Consider File Operation 1
FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
StreamWriter str = new StreamWriter(fs);
str.BaseStream.Seek(0, SeekOrigin.End);
str.Write("mytext.txt.........................");
str.WriteLine(DateTime.Now.ToLongTimeString() + " " +
DateTime.Now.ToLongDateString());
string addtext = "this line is added" + Environment.NewLine;
str.Flush();
str.Close();
fs.Close();
// Close the Stream then Individually you can access the file.
}
File.AppendAllText(path, addtext); // File Operation 2
string readtext = File.ReadAllText(path); // File Operation 3
Console.WriteLine(readtext);
In every File Operation, The File will be Opened and must be Closed prior Opened. Like wise in the Operation 1 you must Close the File Stream for the Further Operations.
You are writing to the file prior to closing your filestream:
using(FileStream fs=new FileStream(path,FileMode.OpenOrCreate))
using (StreamWriter str=new StreamWriter(fs))
{
str.BaseStream.Seek(0,SeekOrigin.End);
str.Write("mytext.txt.........................");
str.WriteLine(DateTime.Now.ToLongTimeString()+" "+DateTime.Now.ToLongDateString());
string addtext="this line is added"+Environment.NewLine;
str.Flush();
}
File.AppendAllText(path,addtext); //Exception occurrs ??????????
string readtext=File.ReadAllText(path);
Console.WriteLine(readtext);
The above code should work, using the methods you are currently using. You should also look into the using statement and wrap your streams in a using block.
File.AppendAllText does not know about the stream you have opened, so will internally try to open the file again. Because your stream is blocking access to the file, File.AppendAllText will fail, throwing the exception you see.
I suggest you used str.Write or str.WriteLine instead, as you already do elsewhere in your code.
Your file is created but contains nothing because the exception is thrown before str.Flush() and str.Close() are called.
using (var fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
using (var sw = new StreamWriter(fs))
{
sw.WriteLine(message);
}
I direct the standard output/error of a process and store it in a string which I log to a file.
I have noticed that not all of the standard output is stored in the text file so I must be hitting the size limit of the string.
Does anyone know of an alternative which would help satisfy this issue?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Logging
{
class Logger
{
private FileStream file = null;
private StreamWriter writer = null;
public Logger(string _path)
{
if (!File.Exists(_path)) File.Create(_path).Dispose();
file = new FileStream(_path, FileMode.Append, FileAccess.Write, FileShare.Write);
writer = new StreamWriter(file);
}
public void Log(string _text)
{
Console.WriteLine(_text);
using (file)
{
writer.WriteLine("[" + DateTime.Now + "] : " + _text);
}
}
}
}
using (file)
You just disposed your file. You can't write to it anymore.
The string type has a limit of 2GB.
Your handling of the file creation and disposal is causing you some difficulty.
Try this for a little cleaner logging code:
const string log = #"logfile path";
public void Log(string _text)
{
try
{
using (TextWriter tw = new StreamWriter(_path, true))
{
tw.WriteLine("[" + DateTime.Now + "] : " + _text);
}
}
catch (Exception)
{
throw;
}
}
I have a file path that might exist or might not exist.
I want to create / override the file, and i have this code:
string filePath = GetFilePath();
using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
xDoc.Save(file);
}
When i call using (FileStream file ...) and the file doesn't exist, it throws an Could not find a part of the path... error.
I am doing something wrong? shouldn't it create the file if doesn't exist?
FileStream can't create intermediate directories that don't exist. This question should help you.
FileMode.OpenOrCreate creates a file if it doesn't exist. If you also need to create the directory:
bool dirExists = System.IO.Directory.Exists(dir);
if(!dirExists)
System.IO.Directory.CreateDirectory(dir);
using(var fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
}
OpenOrCreate
Specifies that the operating system should open a file if it exists;
otherwise, a new file should be created.
try this:
void OpenOrCreateFile()
{
try
{
string filePath = GetFilePath();
EnsureFolder(filePath); //if directory not exist create it
using(var fs = new FileStream(filePath, FileMode.OpenOrCreate))
{
//your code
}
}
catch(Exception ex)
{
//handle exception
}
}
void EnsureFolder(string path)
{
string directoryName = Path.GetDirectoryName(path);
if ((directoryName.Length > 0) && (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
}
You can use StreamWriter has a boolean parameter append to overwrite the file it contents exits
http://msdn.microsoft.com/en-IN/library/36b035cb.aspx
public StreamWriter(
string path,
bool append
)
You can use the below given code
using System;
using System.IO;
using System.Text;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
string fileName = "test.txt";
string textToAdd = "Example text in file";
using (StreamWriter writer = new StreamWriter(fileName, false))
{
writer.Write(textToAdd);
}
}
}
}