I am working on this project still and I am running into a problem. Well here is what I need to do.
When the user clicks the “Save” button, write the selected record to
the file specified in txtFilePath (absolute path not relative) without
truncating the values currently inside and handle any exceptions that arise.
Ok here is my code:
private void Save_Click(object sender, EventArgs e)
{
string filePath = txtFilePath.Text;
if (!File.Exists(filePath))
{
FileStream fs = File.Create(filePath);
fs.Close();
}
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
foreach (string line in employeeList.Items)
{
sw.WriteLine(line);
}
}
}
}
Now when I go onto my program and want to save something from the employeelist.text that its not being saved to the place I am saving it at. I don;t know if I am missing something in my code or what but it will not save. Here is an example:
I add a person name to this list in employeelist and in the textbox I
have a file called C:\employess\employeelist.txt I want to save it to.
I click the save button then I go to that employeelist and it is not
being saved.
I don't know what I am doing wrong I have been looking online for a solution but I haven't found anything yet. Thanks
Some things to double-check:
Make sure you don't have the employeelist.txt file open when you're testing
Make sure you don't have invalid characters in your file name
Make sure your application has permission to save the file to the location you specified
Use the debugger to step-through your code and look for swallowed exceptions -- there must be a reason the file is not created.
Check that your Save_Click event is wired up to your button -- is the code in your example even running?
Once you check those things, you may want to follow this example for the create vs. append requirement of your project:
string path = txtFilePath.Text;
// This text is added only once to the file.
if (!File.Exists(path))
{
using (StreamWriter sw = File.CreateText(path))
{
foreach (var line in employeeList.Items)
sw.WriteLine(line.ToString());
}
}
else
{
using (StreamWriter sw = File.AppendText(path))
{
foreach (var line in employeeList.Items)
sw.WriteLine(line.ToString());
}
}
This will create the file if it doesn't exist, or append to it if it does.
Checking that the file exists and then creating it is a bit unnecessary as this can all be handled by the StreamWriter/FileStream parts. So your above function can be simplified into the following:
public void Save_Click(object sender, EventArgs e)
{
StreamWriter file =
new StreamWriter(txtFilePath.Text, true);//Open and append
foreach (object item in employeeList.Items) {
file.WriteLine(item.toString());
}
file.Close();
}
[Updated]
What are the types of txtFilePath and employeeList the former suggests it's a text box, the later suggests it's bound to a non-GUI element perhaps? (WAG)
You might also want to append a blank line at the end so that on further saves you can tell it was an append rather than one long list (depending on your needs of course)
Starting with .Net Framework 4 you can do it like this:
private void Save_Click(object sender, EventArgs e)
{
File.AppendAllLines(txtFilePath.Text, employeeList.Items);
}
Of course, you probably would want to add a check to have a valid path and a valid enumeration of strings.
If the path looks like a relative one (i.e. doesn't begin with a drive letter), then it will be interpreted that way.
If you put a full path in the text box, does the file get saved in the proper place? If so, perhaps this is what was intended.
If the user doesn't put in a full path, do you have a way to make it one (for example, just sticking C:\ at the beginning)? Or at least can you tell when there isn't a full path, and reject the request?
Related
I have got a project on the go that monitors patients for a vet while they are being operated on and writes the result to a text file. While I was experimenting with the outputting I just let the files save in the Debug folder, which worked fine. However, I've now created a full directory that creates or opens a main folder, and then a sub folder (based on input text from the program), to save the text file into.
private void createDirectory()
{ //create output file in this folder using owner name and current date
//main folder path (contains all files output from system)
string rootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\Horse Monitoring Records";
//sub folder path (each patient has individual subfolder)
string subDirectory = rootDirectory + "\\" + txtPatName.Text + "-" + txtOwnerName.Text;
//file name (patient has file created for each operation)
fileName = subDirectory + "\\" + txtOwnerName.Text + "-" + DateTime.Now.Date.ToString("ddMMyyyy") + ".txt";
if (!Directory.Exists(rootDirectory)) //if main folder does not exist...
{
Directory.CreateDirectory(rootDirectory); //create it in My Documents
}
if (!Directory.Exists(subDirectory)) //if patient sub folder does not exist...
{
Directory.CreateDirectory(subDirectory); //create it in Patient-Owner format
}
if (!File.Exists(fileName)) //if monitoring file does not exist...
{
File.Create(fileName); //create it in Owner-Date format
}
}
This stage works fine, but as soon as you try to save some data to the text file, it throws to a run time error stating that
The file cannot be accessed because it is being used by another process.
The exception is brought up here:
private void saveFileDetails()
{
//Once case details have been entered, create new file using these details and add data input structure
StreamWriter consoleFile = new StreamWriter(fileName);
...
}
When I went and checked out the folder, the relevant sub-folder and file had been created but the text file was blank.
I'm guessing it's something to do with closing the text file after creating the directory, which means it's already open when the system tries to open it. I can't figure out how to sort this issue out though!
The two functions shown above are called like this:
private void btnStart_Click(object sender, EventArgs e)
{
...
//file details entered upon load written to new file - according to PatID
createDirectory();
saveFileDetails();
}
Any suggestions on where to go from here would be very much appreciated!
Thanks,
Mark
The issue here is that you do
if (!File.Exists(fileName)) //if monitoring file does not exist...
{
File.Create(fileName); //create it in Owner-Date format
}
Right before you try to write to the file. Because you've just created it (if it didn't exist), chances are that the operating system hasn't released the file yet.
Like #Jauch mentioned in the comments, you could skip this check completely and use the StreamWriter overload which will create file if it doesn't exist, or append to it if it does.
private void saveFileDetails()
{
//Once case details have been entered, create new file using these details and add data input structure
using (StreamWriter consoleFile = new StreamWriter(fileName, true))
{
// ...
}
}
Alternatively you can use the following to write all of your text at once:
File.AppendAllText(textToWrite, fileName);
File.Create(fileName) returns an open stream to the file which is never closed.
To create an empty file use File.WriteAllBytes(fileName, new byte[0]);
Otherwise the 2 methods can be shortend
private void SaveFileDetails()
{
string subDirectory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"Horse Monitoring Records");
// create the folder hierarchy if not exists. does nothing if already there
Directory.CreateDirectory(subDirectory);
// each patient has individual file
var filepath = Path.Combine(subDirectory,
txtPatName.Text + "-" + txtOwnerName.Text + "-" + DateTime.Now.Date.ToString("yyyyMMdd") + ".txt");
// creates the file if not exists
using (var writer = new StreamWriter(filepath, append: true, encoding: Encoding.UTF8))
{
// write details
}
}
Note:
merged 2 methods
.NET naming conventions applied
changed dateformat to better sort by name in explorer
StreamWriter implements IDisposable, so wrapping it in a using block can manage closing and disposing the writer and ensuring it is available the next time you want to touch that file. It can also manage creating the text file if it doesn't exist, removing the need to explicitly call File.Create.
StreamWriter consoleFile = new StreamWriter(fileName);
becomes
using (StreamWriter writer = File.AppendText("log.txt"))
{
// writing, etc.
}
or
using (StreamWriter writer = new StreamWriter(fileName, true))
{ // true says "append to file if it exists, create if it doesn't"
// writing, etc.
}
Whatever seems more readable to you will work fine.
I'm trying to take the data from two text boxes, and writing it to file without replacing the current stuff already there when a button is pressed. This is what I have so far:
private void button1_Click_1(object sender, EventArgs e)
{
using (StreamWriter sw1 = new StreamWriter("DataNames.txt"))
{
sw1.WriteLine(textBox1.Text);
}
using (StreamWriter sw2 = new StreamWriter("DataNumbers.txt"))
{
sw2.WriteLine(textBox2.Text);
}
}
Right now it takes the input, and replaces whatever is currently in the files so then there is only one line, instead of just adding it to the list. Thanks for the help.
//using (StreamWriter sw1 = new StreamWriter("DataNames.txt"))
//{
// sw1.WriteLine(textBox1.Text);
//}
System.IO.File.AppendAllText("DataNames.txt", textBox1.Text);
Use StreamWriter Constructor (String, Boolean) constructor and pass true for append.
true to append data to the file; false to overwrite the file. If the specified file does not exist, this parameter has no effect, and
the constructor creates a new file.
In your code pass true like:
using (StreamWriter sw1 = new StreamWriter("DataNames.txt",true))
Try this
using (StreamWriter sw2 = new StreamWriter("DataNumbers.txt", true))
{
sw2.WriteLine(textBox2.Text);
}
Second argument true tells that file needs to be appended instead of overwriting. StreamWriter(String, Boolean)
Switch the
new StreamWriter("DataNumbers.txt")
to
File.CreateText("DataNames.txt")
You can find more info at:
http://msdn.microsoft.com/en-us/library/system.io.file.appendtext.aspx
You are making two separate instance of stream writer, and they are both attempting to write to the same file, so they are competing with each other - that's why you are seeing the overwriting.
If you want to add text to the end of a file, the best way to do so is probably File.AppendAllText: http://msdn.microsoft.com/en-us/library/ms143356.aspx
private void button1_Click_1(object sender, EventArgs e)
{
System.IO.File.AppendAllText("DataNames.txt", textBox1.Text + textBox2.Text);
}
AppendAllText is quite useful if you are doing small, relatively infrequent appends as you can just send strings into it without thinking as opposed to making sure you are using your stream writer.
I am making simple tool for manipulating images in a database. I want to show the output result in a txt file and because the outcome may be different each time, I want the file to be rewritten with the fresh data every time the data is executed.
Also I want (if possible) to use some default location where the txt file will be created even though I have an App.Config file and that's also an option.
The problem I am having is with this code:
string Resultfile =
System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) +
"\\PictureStatus.txt";
FileStream strm = new FileStream(Resultfile , FileMode.Create);
TextWriter tw = new StreamWriter(strm);
This populates the PictureStatus.txt only once and then I get the same text over and over again. I noticed that if I use some random destination the file is updated. Not sure if it's just random behavior or have something to do with using MyDocuments, but what I need is a way to be sure that I'll rewrite the file with the new data each time, and if possible, use some default destination that will work for other people.
You can try something like this
public partial Form2 : Form
{
public string path = Environment.CurrentDirectory + "/" + "Name.txt";
public Form2()
{
InitializeComponent();
if (!File.Exists(path))
{
File.Create(path);
}
}
private void button2_Click(object sender, EventArgs e)
{
using (StreamWriter sw = new StreamWriter(path, true))
{
sw.WriteLine("This text will be writen in the txt file", true);
sw.Close();
}
}
}
I have add to the button, when I pressed it will be written in the next line every time. If you remove "true" from code, it will be overwritten every time.
Alright it has come to this. I searched this website among many others and no one can seem to give me a straight answer so I'm going to try just asking outright. Been on this issue for about a solid 3 days and I can't afford to waste any more time on it.
Goal: The app I am building is in WPF and is going to be used as a bug tracker for a project my design team and I will be undertaking soon. Since we are going to be building a game in C++ most of the errors that occur will have a visual element to them so I inlcuded functionality to provide an image of the error in question when the user adds a bug to the list. I then take that image and save it to a local directory (for testing). Now the image path in the Error object points to a path that leads to the local directory. This functionality has been tested and works fine. My problem showes up when I want to delete a bug from the list. I am getting that very infamous "IO Exception" saying that the image I want to delete is being used by another process.
So Far: At first I tried very elegant solutions, but as with all things you get to a point where you just want to see if you can get the thing to even work at all. So I am at the point where most of the code I am using is experimental and radical. So please when looking at it note that the code being used is out of desperation, so any "simple" solutions have probably already been tried (I did research this a lot becuase I hate having to do this). Things i can think of off the top of my head are the obsurd amount of disposes and forced garbage collections being called so please to not comment on the negative nature of this practice, I am well aware :).
The Code
Saving image to local directory
public void OnBrowseClick()
{
Microsoft.Win32.OpenFileDialog openBox = new Microsoft.Win32.OpenFileDialog();
// Show dialog box to user and grab output
Nullable<bool> result = openBox.ShowDialog();
if (result == true)
{
// Create temp variable to hold local path string
string localPath = Directory.GetCurrentDirectory();
// Grab the extension of the specified file path
string extension = openBox.FileName.Substring(openBox.FileName.LastIndexOf("\\"));
// Add extension to local path
localPath += extension;
// Create local copy of image at given file path (being ridiculous at this point)
using (Stream stream = new FileStream(openBox.FileName, FileMode.Open, FileAccess.ReadWrite))
{
using (Bitmap bmp = LoadImage(stream))
{
using (Bitmap temp = (Bitmap)bmp.Clone())
{
temp.Save(localPath);
temp.Dispose();
}
bmp.Dispose();
}
stream.Dispose();
}
// Set the URL in the image text box (UI stuff)
LocalError.ImagePath = localPath;
}
}
The following is the LoadImage function that is used in the function above
private Bitmap LoadImage(Stream stream)
{
Bitmap retval = null;
using (Bitmap bitmap = new Bitmap(stream))
{
retval = new Bitmap(bitmap.Width, bitmap.Height, bitmap.PixelFormat);
using (Graphics gdi = Graphics.FromImage(retval))
{
gdi.DrawImageUnscaled(bitmap, 0, 0);
gdi.Flush();
gdi.Dispose();
bitmap.Dispose();
}
}
// Garbage collection here to be safe
GC.WaitForPendingFinalizers();
GC.Collect();
return retval;
}
And finally we come to where I try to delete the image
public void OnDeleteClick()
{
// Ask user to make sure they want to delete selected item(s)
MessageBoxResult result = MessageBox.Show("Are you sure you want to delete selected item(s) from the list?",
"Delete", MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
for( int i = 0; i < Parent.ErrorListControl.ErrorDataGrid.SelectedItems.Count; ++i)
{
// Get path to image
string path = (Parent.ErrorListControl.ErrorDataGrid.SelectedItems[i] as Error).ImagePath;
// Even tried calling garbage collection here!!!!!
System.GC.WaitForPendingFinalizers();
System.GC.Collect();
File.Delete(path);
// Remove the error from the error list
Parent.ErrorListVM.ErrorList.Remove((Error)Parent.ErrorListControl.ErrorDataGrid.SelectedItems[i]);
// Decrement counter because we altered the list while in a loop
i--;
}
}
}
Notes: If anyone would like me to explain anything further or if you need to know something I left out please just ask I will get back to you ASAP! Any suggestions are helpful at this point I have absolutley no idea what I am doing wrong. I generally only program in a C++ environment so I tend to manage my own memory this whole "garbage collection" thing is really throwing a wrench in our project! (Off topic note: I do not know why I am not getting any color highlighting so I apologize to anyone who takes the time to read this).
Here's a simple way to do what you want. In this example, I'm using Path.GetTempFileName() to generate a random file name in the local user's temp directory. If you don't need to persist the files then it's a good place to store them temporarily. Also, the user could theoretically import two files with the same name. So you want to use some kind of random filename generation or other mechanism to avoid conflicts.
private void browseButton_Click(object sender, RoutedEventArgs e)
{
var openFileDialog = new Microsoft.Win32.OpenFileDialog();
if (openFileDialog.ShowDialog(this) == true)
{
using (Bitmap originalImage = new Bitmap(openFileDialog.FileName))
{
string tempFileName = System.IO.Path.GetTempFileName();
originalImage.Save(tempFileName);
// LocalError.LocalPath
LocalPath = tempFileName;
}
}
}
private void deleteButton_Click(object sender, RoutedEventArgs e)
{
if (File.Exists(LocalPath))
{
File.Delete(LocalPath);
}
}
Although a simple File.Copy should suffice as long as you have the right paths, I was just providing a solution that matched your question.
EDIT:
Actually the current directory does not seem to be changed by the OpenFileDialog. I could swear that it did at some point. So I don't think this is your problem. Regardless, this code still works for me and you shouldn't require anything more complicated than this.
EDIT #2:
It seems the lock is actually caused by the image being databound to the view and presumably locked by the BitmapSource. You should be able to create it without locking the file. Generally, this is slower so don't do it this way unless you need to be able to modify or delete the file.
bitmapSource = new BitmapImage();
bitmapSource.BeginInit();
bitmapSource.CacheOption = BitmapCacheOption.OnLoad;
bitmapSource.CreateOption = BitmapCreateOptions.IgnoreImageCache;
bitmapSource.UriSource = new Uri(ImagePath, UriKind.Absolute);
bitmapSource.EndInit();
Since your LoadImage method does simple copy of the image, why not use File.Copy(source, dest) and avoid all the bitmaps, drawings, etc? Your goal might be to modify local bitmap after it's created, but it can still be done after copy.
Also, when using the using block, explicit .Dispose() is not required, as using block does it for you:
using (var obj = new SomeDisposableObject())
{
// code here
// obj.Dispose(); <-- not needed, since...
} // ...at this point obj.Dispose is called automatically.
I have a textbox where a user can input their email, what I want to do is make it so that when they click a submit button. That email will be saved into a text file ( on my server ) called emails.txt
I managed to get this working using System.IO and then using the File.WriteAll method. However I want to make it so that it will add the email to the list ( on a new line ) rather then just overwriting whats already in there.
I've seen people mention using Append, but I can't quite grasp how to get it working.
This is my current code (that overwrites instead of appending).
public partial class _Default : Page
{
private string path = null;
protected void Page_Load(object sender, EventArgs e)
{
path = Server.MapPath("~/emails.txt");
}
protected void emailButton_Click(object sender, EventArgs e)
{
File.WriteAllText(path, emailTextBox.Text.Trim());
confirmEmailLabel.Text = "Thank you for subscribing";
}
}
You can use StreamWriter to get working with text file. The WriteLine method in true mode append your email in new line each time....
using (StreamWriter writer = new StreamWriter("email.txt", true)) //// true to append data to the file
{
writer.WriteLine("your_data");
}
From the official MSDN documentation:
using (StreamWriter w = File.AppendText("log.txt"))
{
MyWriteFunction("Test1", w);
MyWriteFunction("Test2", w);
}
Use StreamWriter in Append mode. Write your data with WriteLine(data).
using (StreamWriter writer = new StreamWriter("emails.txt", true))
{
writer.WriteLine(email);
}
Seems like a very easy question with a very easy answer: Open existing file, append a single line
If you post the current code, we can modify that to append instead of overwrite.