I am writing a program where I have 2 listboxes with the same data but the one listbox items are update with the student name and their TOTAL score and the other with the student name and each individual judge score next to the student name. Everything is going good so far but now I am stuck... I have two methods Save() and SaveAs() where Save() automatically writes data to "FormData.bin" and SaveAs() lets the user enter their own file name.
Is it possible to re-write the Save() method so that when I click save it saves the current data to the file that is open like in MS Word when you are typing in document and just click save to add new typed data to current file. Here is my Save() method I wrote.
public void SaveEntry()
{
int itemsCount = Math.Min(lstbxStudents.Items.Count, lstbxStudentScore.Items.Count);
saveFileDialog1.InitialDirectory = Application.StartupPath;
saveFileDialog1.FileName = "FormData.bin";
{
try
{
using (FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create))
using (BinaryWriter Save = new BinaryWriter(fs))
{
Save.Write(cmbbxAge.Text);
Save.Write(cmbbxBelt.Text);
Save.Write(cmbbxCategorie.Text);
Save.Write(cmbbxGender.Text);
Save.Write(cmbbxGup.Text);
Save.Write(txtJudge1.Text);
Save.Write(txtJudge2.Text);
Save.Write(txtJudge3.Text);
Save.Write(txtJudge4.Text);
Save.Write(txtJudge5.Text);
Save.Write(txtOperator.Text);
Save.Write(txtPos1.Text);
Save.Write(txtPos2.Text);
Save.Write(txtPos3.Text);
Save.Write(txtPos4.Text);
Save.Write(txtPos5.Text);
for (int i = 0; i < itemsCount; i++)
{
Save.Write(lstbxStudents.Items[i].ToString());
Save.Write(lstbxStudentScore.Items[i].ToString());
}
Save.Close();
fs.Close();
}
}
catch (Exception error)
{
MessageBox.Show(error.Message, "CTSD Forms");
}
}
}
Thank you in advance
Here is image of Form
Window Form
If I understood correctly what you are trying to achieve is to append text rather than overwrite it. Take a look upon the StreamWriter class that also allows to specify if you want to append the data or not when constructing the instance. It also allows to create/append to the file directly, without the need of a Stream.
Also, consider using proper names for variables:
Save is an action, not an object. writer would be better.
By using Write in the way you showed in your code, you will end with all the texts appended with no separators. You should consider using WriteLine functions.
[edit upon clarifications]
SaveEntry should take a parameter to specify if save is done as SaveAs or Save. First save should always be a SaveAs. Also filename should be saved in the context (your form class, but it is better to have a "view model")
private String _currentFileName;
public void SaveEntry(bool saveAs)
{
if (saveAs || String.IsNullOrEmpty(_currentFileName))
{
saveFileDialog1.InitialDirectory = Application.StartupPath;
saveFileDialog1.FileName = "FormData.bin";
var result = saveFileDialog1.ShowDialog();
// TODO: handle user cancellation
_currentFileName = saveFileDialog1.FileName;
}
using (var writer = new StreamWriter(_currentFileName))
{
// TODO: do stuff with your writer
}
}
Related
I'm trying to detect if a file exists at runtime, if not, create it. However I'm getting this error when I try to write to it:
The process cannot access the file 'myfile.ext' because it is being used by another process.
string filePath = string.Format(#"{0}\M{1}.dat", ConfigurationManager.AppSettings["DirectoryPath"], costCentre);
if (!File.Exists(filePath))
{
File.Create(filePath);
}
using (StreamWriter sw = File.AppendText(filePath))
{
//write my text
}
Any ideas on how to fix it?
File.Create(FilePath).Close();
File.WriteAllText(FileText);
I want to update this answer to say that this is not really the most efficient way to write all text. You should only use this code if you need something quick and dirty.
I was a young programmer when I answered this question, and back then I thought I was some kind of genius for coming up with this answer.
The File.Create method creates the file and opens a FileStream on the file. So your file is already open. You don't really need the file.Create method at all:
string filePath = #"c:\somefilename.txt";
using (StreamWriter sw = new StreamWriter(filePath, true))
{
//write to the file
}
The boolean in the StreamWriter constructor will cause the contents to be appended if the file exists.
When creating a text file you can use the following code:
System.IO.File.WriteAllText("c:\test.txt", "all of your content here");
Using the code from your comment. The file(stream) you created must be closed. File.Create return the filestream to the just created file.:
string filePath = "filepath here";
if (!System.IO.File.Exists(filePath))
{
System.IO.FileStream f = System.IO.File.Create(filePath);
f.Close();
}
using (System.IO.StreamWriter sw = System.IO.File.AppendText(filePath))
{
//write my text
}
FileStream fs= File.Create(ConfigurationManager.AppSettings["file"]);
fs.Close();
File.Create returns a FileStream. You need to close that when you have written to the file:
using (FileStream fs = File.Create(path, 1024))
{
Byte[] info = new UTF8Encoding(true).GetBytes("This is some text in the file.");
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
You can use using for automatically closing the file.
I updated your question with the code snippet. After proper indenting, it is immediately clear what the problem is: you use File.Create() but don't close the FileStream that it returns.
Doing it that way is unnecessary, StreamWriter already allows appending to an existing file and creating a new file if it doesn't yet exist. Like this:
string filePath = string.Format(#"{0}\M{1}.dat", ConfigurationManager.AppSettings["DirectoryPath"], costCentre);
using (StreamWriter sw = new StreamWriter(filePath, true)) {
//write my text
}
Which uses this StreamWriter constructor.
I know this is an old question, but I just want to throw this out there that you can still use File.Create("filename")", just add .Dispose() to it.
File.Create("filename").Dispose();
This way it creates and closes the file for the next process to use it.
This question has already been answered, but here is a real world solution that
checks if the directory exists and adds a number to the end if the text file
exists. I use this for creating daily log files on a Windows service I wrote. I
hope this helps someone.
// How to create a log file with a sortable date and add numbering to it if it already exists.
public void CreateLogFile()
{
// filePath usually comes from the App.config file. I've written the value explicitly here for demo purposes.
var filePath = "C:\\Logs";
// Append a backslash if one is not present at the end of the file path.
if (!filePath.EndsWith("\\"))
{
filePath += "\\";
}
// Create the path if it doesn't exist.
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
// Create the file name with a calendar sortable date on the end.
var now = DateTime.Now;
filePath += string.Format("Daily Log [{0}-{1}-{2}].txt", now.Year, now.Month, now.Day);
// Check if the file that is about to be created already exists. If so, append a number to the end.
if (File.Exists(filePath))
{
var counter = 1;
filePath = filePath.Replace(".txt", " (" + counter + ").txt");
while (File.Exists(filePath))
{
filePath = filePath.Replace("(" + counter + ").txt", "(" + (counter + 1) + ").txt");
counter++;
}
}
// Note that after the file is created, the file stream is still open. It needs to be closed
// once it is created if other methods need to access it.
using (var file = File.Create(filePath))
{
file.Close();
}
}
I think I know the reason for this exception. You might be running this code snippet in multiple threads.
you can just use using keyword around File.Create(path) to finalize the process
using(File.Create(path));
Try this: It works in any case, if the file doesn't exists, it will create it and then write to it. And if already exists, no problem it will open and write to it :
using (FileStream fs= new FileStream(#"File.txt",FileMode.Create,FileAccess.ReadWrite))
{
fs.close();
}
using (StreamWriter sw = new StreamWriter(#"File.txt"))
{
sw.WriteLine("bla bla bla");
sw.Close();
}
Another way to say it is this: I want a program that logs the amount of times you've pressed a button. To do this I'd need a StreamWriter to write to a text document the number of times and a StreamReader to read the number of times as to display it when you start up the program.
If there is an easier way, feel free to share it. But my question is:
How can I make it so that it only writes in one line, and whenever it wants to write again to it, deletes the whole thing and puts in the new input?
The below will write to the file C:\log.txt. By setting the 2nd parameter to false, it will overwrite the contents of the file.
using (StreamWriter writer = new StreamWriter("C:\\log.txt", false))
{
writer.Write("blah");
}
To guarantee the file is always overwritten every time it is used, place the StreamWriter call in a different method like so:
public void DoStuff()
{
for(int i = 0; i < 20; i++)
{
WriteStuff("blah" + i);
}
}
private void WriteStuff(string text)
{
using (StreamWriter writer = new StreamWriter("C:\\log.txt", false))
{
writer.Write(text);
}
}
I am trying to write a program to me should be a lot easier than it is proving.
I have a form with text boxes that asks the user to enter their details e.g. Name, Address etc.. What I am trying to achieve is to save the data from the text boxes into a .txt file when the user hits the save button.
I am able to create the file but the data will not save into the file.
I have posted my code below, and any help you may have will be greatly appreciated.
private void btnSave_Click(object sender, EventArgs e)
{
string file_name = "e:\\test1.txt";
System.IO.StreamWriter objWriter;
objWriter = new System.IO.StreamWriter(file_name, true);
objWriter.Write(txtName.Text);
objWriter.Write(txtAddress.Text);
objWriter.Write(txtEmail.Text);
objWriter.Write(txtPhone.Text);
MessageBox.Show("Details have been saved");
}
It would be more practical to use using at the beginning of the code line where StreamWriter is present. This is to ensure data are Disposed, you'll need this to unlock the data from the stream.
When writing data:
using (StreamWriter objWriter = new StreamWriter("test1.txt"))
{
objWriter.Write(txtName.Text);
objWriter.Write(txtAddress.Text);
objWriter.Write(txtEmail.Text);
objWriter.Write(txtPhone.Text);
MessageBox.Show("Details have been saved");
}
When reading saved data, let's use a listbox just to have an example:
foreach (var line in File.ReadAllLines("test1.txt"))
{
listBox1.Items.Add(line);
}
Hope this helps!
It is a good practice to wrap local variables implementing IDisposable into the using statement:
using (StreamWriter objWriter = new StreamWriter(file_name, true))
{
objWriter.Write(txtName.Text);
objWriter.Write(txtAddress.Text);
objWriter.Write(txtEmail.Text);
objWriter.Write(txtPhone.Text);
}
This also has a positive side effect: the stream is flushed and closed right after execution of the using statement.
Suggestion: Consider using WriteLine instead of Write, because probably you need a delimiter between string values.
Call StreamWriter.Flush method after you done:
objWriter.Flush();
Clears all buffers for the current writer and causes any buffered data to be written to the underlying stream.
You could also do this using File.WriteAllText method:
var line = string.Join(" ", txtName.Text, txtAddress.Text, txtEmail.Text,txtPhone.Text);
File.WriteAllText(file_name, line);
---short version:
When I get to the while (!checkReader.EndOfStream) every time after the first, it says EndOfStream = true.
---more detail:
A user will upload a file using an Ajax AsyncFileUpload control. I take that file, ensure it's a very specific format of csv that we use and spit it out into a GridView. This all works great the first time through: I get the file, parse it out, and it displays great.
But, if I call this same code again anytime during the user's session the StreamReader.EndOfStream = true.
For example, a user uploads a file and I spit it out into the GridView. Oops! User realizes there are headers... I have a checkbox available with an event handler that will call the method below to re-read the original file (it's stored in a session variable). User checks the box, event fires, method gets called, but my EndOfStream is now true.
I thought that using () would change that flag and I have tried adding checkReader.DiscardBufferedData just after the while loop below, but neither of those seem to have any affect.
What am I doing wrong?
private void BuildDataFileGridView(bool hasHeaders)
{
//read import file from the session variable
Stream theStream = SessionImportFileUpload.PostedFile.InputStream;
theStream.Position = 0;
StringBuilder sb = new StringBuilder();
using (StreamReader checkReader = new StreamReader(theStream))
{
while (!checkReader.EndOfStream)
{
string line = checkReader.ReadLine();
while (line.EndsWith(","))
{
line = line.Substring(0, line.Length - 1);
}
sb.AppendLine(line);
}
}
using (TextReader reader = new StringReader(sb.ToString()))
{
//read the file in and shove it out for the client
using (CsvReader csv = new CsvReader(reader, hasHeaders, CsvReader.DefaultDelimiter))
{
sDataInputTable = new DataTable();
try
{
//Load the DataTable with csv values
sDataInputTable.Load(csv);
}
catch
{
DisplayPopupMessage("ERROR: A problem was encountered");
}
//Copy only the first 10 rows into a temp table for display.
DataTable displayDataTable = sDataInputTable.Rows.Cast<System.Data.DataRow>().Take(10).CopyToDataTable();
MyDataGridView.DataSource = displayDataTable;
MyDataGridView.DataBind();
}
}
}
Edit:
SessionImportFileUpload is the actual Ajax AsyncFileUpload control being stored as a session variable (this was already the case as a previous person wrote other stuff in that uses it).
You are storing the posted file stream in Session. This is not correct, because the stream is not the data, but rather the mechanism to read the data. The file is uploaded only once, during a single POST request, and you won't be able to read from the same stream again later. Usually you even cannot rewind the stream to re-read it.
That's why I suggest to read the posted file stream only once and put the whole content into Session - this way the content will be reusable, and you'll be able to reprocess it as many times as you need.
Hi all i write a code to write my last row of datagrid view to a file as follows
private void Save_Click(object sender, EventArgs e)
{
if (dataGridView1.Rows.Count > 0)
{
List<string> lstContent = new List<string>();
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if ((string)row.Cells[0].Value == "FileControl")
{
lstContent.Add((string)row.Cells[1].Value);
string mydata = string.Join(",", lstContent.ToArray());
using (StreamWriter sw = new StreamWriter(Append.FileName, true))
{
sw.WriteLine();
sw.Write(mydata);
}
}
}
}
}
But if i click multiple times on save this is writing that line multiple times what i need is if already that line exists in the file i have to replace that line with new line. Any help please
Your StreamWriter is explicitly using the file with append = true. Change the second parameter of the constructor to false if you want to overwrite the file each time. Docs are here. Quote:
append
Type: System.Boolean
Determines
whether data is to be appended to the
file. If the file exists and append is
false, the file is overwritten. If the
file exists and append is true, the
data is appended to the file.
Otherwise, a new file is created.
Revised code:
using (StreamWriter sw = new StreamWriter(Append.FileName, false))
{
sw.WriteLine();
sw.Write(mydata);
}
Replacing a given line in your file rather than just overwriting the whole file is a lot more difficult - this code is not going to get it done. StreamWriter is not great for this, you need random access and the ability to replace one data segment (line) by a different data segment of different length, which is an expensive operation on disk.
You might want to keep the files in memory as a container of Strings and do your required line replacement within the container, then write out the file to disk using File.WriteAllLines - that's if the file is not too big.