How to read and sort a text file - c#

How do i read and sort a text file
sorry if this is an easy question I'm new to coding. I've tried many online solution but none seems to fix my problem:
namespace Login_but_it_hopefully_works
{
public partial class Leaderboard : Form
{
string Line = "";
private string filepath1 = #"Compdetails.txt";
FileStream readerStream = new FileStream("Compdetails.txt", FileMode.Open);
string[] content = null;
public Leaderboard()
{
InitializeComponent();
}
public object ListReadFile { get; private set; }
private void bttn_load_Click(object sender, EventArgs e)
{
string[] content = null;
//Read the content
using (StreamReader CompTXT = File.OpenText(filepath1))
{
content = CompTXT.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
//Remove the entries in the file
readerStream.SetLength(0);
}
FileStream writerStream = new FileStream(#"Desktop\Source\text.txt", FileMode.OpenOrCreate);
using (StreamWriter writer = new StreamWriter(writerStream))
{
//Sort the content and write back to the same file
Array.Sort(content);
writer.Write(string.Join(Environment.NewLine, content));
}
}
}
}
The error is:
Additional information: The process cannot access the file
'E:\CS\Login\Login but it hopefully works\bin\Debug\Compdetails.txt'
because it is being used by another process and the line is " using
(StreamReader CompTXT = File.OpenText(filepath3))"

Remove the 2 lines involving readerStream. They are not accomplishing what do you think they are, but they are causing that error. :-) Your next task will be to overwrite the file rather than append to it.
To elaborate on the cause of the error: having that field declared in the class and initialized by opening a stream causes the file to be locked for as long as an instance of the class exists. When you then call the button event method and try to open another stream with another lock on the same file, an exception results.

Related

Streamwriter will not overwrite file, keeps appending or writes only the first line

Been looking through other people's answers and nothing seems to work.
Here is my code:
public void TaskOnClick() //getting multi-values
{
foreach (string inputJson in File.ReadLines("Assets/Text/multi-import.txt"))
{
string temperature = GetTemperatureByRegex(inputJson);
Debug.Log(temperature);
string filename = "Assets/Text/TEMP/multi-export.txt";
{
using (StreamWriter writeFile = new StreamWriter(filename, false))
{
writeFile.AutoFlush = true;
Console.SetOut(writeFile);
writeFile.WriteLineAsync(temperature.ToString());
}
}
}
}
The idea is that my parsing script gets my data and then streamwriter writes the data to a txt file. Problem is that streamwriter keeps appending the txt file instead of overwriting the file.
Whenever I try to use filestream it overwrites the file, yes, but only the first line of the data gets written, no matter what I tried.
My username speaks for itself...
What you do wrong is creating StreamWriter inside a loop. If you provide an overwrite settings it will only write 1 line.
public void TaskOnClick() //getting multi-values
{
string filename = "Assets/Text/TEMP/multi-export.txt";
using (StreamWriter writeFile = new StreamWriter(filename, false))
{
foreach (string inputJson in File.ReadLines("Assets/Text/multi-import.txt"))
{
string temperature = GetTemperatureByRegex(inputJson);
Debug.Log(temperature);
writeFile.AutoFlush = true;
Console.SetOut(writeFile);
writeFile.WriteLine(temperature.ToString());
}
}
}
But there is a shorter way of doing this with the help of LINQ.
public void TaskOnClick() //getting multi-values
{
string filename = "Assets/Text/TEMP/multi-export.txt";
var tempratures = File.ReadAllLines("Assets/Text/multi-import.txt")
.Select(GetTemperatureByRegex).ToArray();
File.WriteAllLines(filename,tempratures); // it creates a new file or overwrites
}
I have to state that above method may be dangerous if input file is too large. Because it reads entire file into memory.
Why don’t you just delete the file before opening the stream writer?
if(File.Exists(filename)){
File.Delete(filename);
}
//here whatever you need to do next

Empty file saved after stream object write line command [duplicate]

There are a lot of different ways to read and write files (text files, not binary) in C#.
I just need something that is easy and uses the least amount of code, because I am going to be working with files a lot in my project. I only need something for string since all I need is to read and write strings.
Use File.ReadAllText and File.WriteAllText.
MSDN example excerpt:
// Create a file to write to.
string createText = "Hello and Welcome" + Environment.NewLine;
File.WriteAllText(path, createText);
...
// Open the file to read from.
string readText = File.ReadAllText(path);
In addition to File.ReadAllText, File.ReadAllLines, and File.WriteAllText (and similar helpers from File class) shown in another answer you can use StreamWriter/StreamReader classes.
Writing a text file:
using(StreamWriter writetext = new StreamWriter("write.txt"))
{
writetext.WriteLine("writing in text file");
}
Reading a text file:
using(StreamReader readtext = new StreamReader("readme.txt"))
{
string readText = readtext.ReadLine();
}
Notes:
You can use readtext.Dispose() instead of using, but it will not close file/reader/writer in case of exceptions
Be aware that relative path is relative to current working directory. You may want to use/construct absolute path.
Missing using/Close is very common reason of "why data is not written to file".
FileStream fs = new FileStream(txtSourcePath.Text,FileMode.Open, FileAccess.Read);
using(StreamReader sr = new StreamReader(fs))
{
using (StreamWriter sw = new StreamWriter(Destination))
{
sw.Writeline("Your text");
}
}
The easiest way to read from a file and write to a file:
//Read from a file
string something = File.ReadAllText("C:\\Rfile.txt");
//Write to a file
using (StreamWriter writer = new StreamWriter("Wfile.txt"))
{
writer.WriteLine(something);
}
using (var file = File.Create("pricequote.txt"))
{
...........
}
using (var file = File.OpenRead("pricequote.txt"))
{
..........
}
Simple, easy and also disposes/cleans up the object once you are done with it.
#AlexeiLevenkov pointed me at another "easiest way" namely the extension method. It takes just a little coding, then provides the absolute easiest way to read/write, plus it offers the flexibility to create variations according to your personal needs. Here is a complete example:
This defines the extension method on the string type. Note that the only thing that really matters is the function argument with extra keyword this, that makes it refer to the object that the method is attached to. The class name does not matter; the class and method must be declared static.
using System.IO;//File, Directory, Path
namespace Lib
{
/// <summary>
/// Handy string methods
/// </summary>
public static class Strings
{
/// <summary>
/// Extension method to write the string Str to a file
/// </summary>
/// <param name="Str"></param>
/// <param name="Filename"></param>
public static void WriteToFile(this string Str, string Filename)
{
File.WriteAllText(Filename, Str);
return;
}
// of course you could add other useful string methods...
}//end class
}//end ns
This is how to use the string extension method, note that it refers automagically to the class Strings:
using Lib;//(extension) method(s) for string
namespace ConsoleApp_Sandbox
{
class Program
{
static void Main(string[] args)
{
"Hello World!".WriteToFile(#"c:\temp\helloworld.txt");
return;
}
}//end class
}//end ns
I would never have found this myself, but it works great, so I wanted to share this. Have fun!
These are the best and most commonly used methods for writing to and reading from files:
using System.IO;
File.AppendAllText(sFilePathAndName, sTextToWrite);//add text to existing file
File.WriteAllText(sFilePathAndName, sTextToWrite);//will overwrite the text in the existing file. If the file doesn't exist, it will create it.
File.ReadAllText(sFilePathAndName);
The old way, which I was taught in college was to use stream reader/stream writer, but the File I/O methods are less clunky and require fewer lines of code. You can type in "File." in your IDE (make sure you include the System.IO import statement) and see all the methods available. Below are example methods for reading/writing strings to/from text files (.txt.) using a Windows Forms App.
Append text to an existing file:
private void AppendTextToExistingFile_Click(object sender, EventArgs e)
{
string sTextToAppend = txtMainUserInput.Text;
//first, check to make sure that the user entered something in the text box.
if (sTextToAppend == "" || sTextToAppend == null)
{MessageBox.Show("You did not enter any text. Please try again");}
else
{
string sFilePathAndName = getFileNameFromUser();// opens the file dailog; user selects a file (.txt filter) and the method returns a path\filename.txt as string.
if (sFilePathAndName == "" || sFilePathAndName == null)
{
//MessageBox.Show("You cancalled"); //DO NOTHING
}
else
{
sTextToAppend = ("\r\n" + sTextToAppend);//create a new line for the new text
File.AppendAllText(sFilePathAndName, sTextToAppend);
string sFileNameOnly = sFilePathAndName.Substring(sFilePathAndName.LastIndexOf('\\') + 1);
MessageBox.Show("Your new text has been appended to " + sFileNameOnly);
}//end nested if/else
}//end if/else
}//end method AppendTextToExistingFile_Click
Get file name from the user via file explorer/open file dialog (you will need this to select existing files).
private string getFileNameFromUser()//returns file path\name
{
string sFileNameAndPath = "";
OpenFileDialog fd = new OpenFileDialog();
fd.Title = "Select file";
fd.Filter = "TXT files|*.txt";
fd.InitialDirectory = Environment.CurrentDirectory;
if (fd.ShowDialog() == DialogResult.OK)
{
sFileNameAndPath = (fd.FileName.ToString());
}
return sFileNameAndPath;
}//end method getFileNameFromUser
Get text from an existing file:
private void btnGetTextFromExistingFile_Click(object sender, EventArgs e)
{
string sFileNameAndPath = getFileNameFromUser();
txtMainUserInput.Text = File.ReadAllText(sFileNameAndPath); //display the text
}
Or, if you are really about lines:
System.IO.File also contains a static method WriteAllLines, so you could do:
IList<string> myLines = new List<string>()
{
"line1",
"line2",
"line3",
};
File.WriteAllLines("./foo", myLines);
It's good when reading to use the OpenFileDialog control to browse to any file you want to read. Find the code below:
Don't forget to add the following using statement to read files: using System.IO;
private void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
textBox1.Text = File.ReadAllText(openFileDialog1.FileName);
}
}
To write files you can use the method File.WriteAllText.
class Program
{
public static void Main()
{
//To write in a txt file
File.WriteAllText("C:\\Users\\HP\\Desktop\\c#file.txt", "Hello and Welcome");
//To Read from a txt file & print on console
string copyTxt = File.ReadAllText("C:\\Users\\HP\\Desktop\\c#file.txt");
Console.Out.WriteLine("{0}",copyTxt);
}
}
private void Form1_Load(object sender, EventArgs e)
{
//Write a file
string text = "The text inside the file.";
System.IO.File.WriteAllText("file_name.txt", text);
//Read a file
string read = System.IO.File.ReadAllText("file_name.txt");
MessageBox.Show(read); //Display text in the file
}
Reading from file
string filePath = #"YOUR PATH";
List<string> lines = File.ReadAllLines(filePath).ToList();
Writing to file
List<string> lines = new List<string>();
string a = "Something to be written"
lines.Add(a);
File.WriteAllLines(filePath, lines);
Simply:
String inputText = "Hello World!";
File.WriteAllText("yourfile.ext",inputText); //writing
var outputText = File.ReadAllText("yourfile.ext"); //reading
You're looking for the File, StreamWriter, and StreamReader classes.

C# Why is StreamWriter writing empty lines after each time it writes to the file?

I know this is a bit of a "Day one" question, but I'm still having trouble understanding why my Stream writer is writing empty lines after each time it writes
namespace PostFinder
{
class HistorySaver
{
public static void Save(string item, string path)
{
StreamReader sre = new StreamReader(path);
string historyList = sre.ReadToEnd();
sre.Dispose();
StreamWriter sr = new StreamWriter(path);
sr.WriteLine(historyList+sr.NewLine+item);
sr.Dispose();
}
}
}
sr.WriteLine(historyList+sr.NewLine+item);
The .WriteLine() method puts an end-of-line character after the contents you pass to it. If you don't want that character, use .Write().
It looks like all you are wanting to do is append text to a file, so there is really no need to open a streamreader to read in the existing contents and then write them back out with your new content.
You can use the below to do all that you want in one step. If the input path file doesn't exist it will create a new one, and if it already exists it will just append your new item.
namespace PostFinder
{
class HistorySaver
{
public static void Save(string item, string path)
{
File.AppendAllText(path, item + Environment.NewLine);
}
}
}

System.IO.IOException: 'The process cannot access the file '#.txt' because it is being used by another process.'

I am new to programming and I have a question. If I have two functions, one creates a text file and writes into it, while the other opens the same text file and reads from it.
The error I get is:
System.IO.IOException: 'The process cannot access the file '#.txt'
because it is being used by another process.'
I have tried setting seperate timers to each of the functions but it still does not work. I think the best way would be that the function two does not start until function one ends.
Can you help me achieve this?
Thank you very much!
Mike
Source code:
public Form1() {
InitializeComponent();
System.Timers.Timer timerButtona1 = new System.Timers.Timer();
timerButtona1.Elapsed += new ElapsedEventHandler(tickTimera1);
timerButtona1.Interval = 3003;
timerButtona1.Enabled = true;
}
private async void tickTimera1(object source, ElapsedEventArgs e) {
function1();
function2();
}
void function1() {
List<string> linki = new List<string>();
linki.Add("https://link1.net/");
linki.Add("https://link2.net/");
linki.Add("https://link3.net/");
List<string> fileNames = new List<string>();
fileNames.Add("name1");
fileNames.Add("name2");
fileNames.Add("name3");
for (int x = 0; x < fileNames.Count; x++) {
GET(linki[x], fileNames[x]);
//System.Threading.Thread.Sleep(6000);
}
}
async void GET(string link, string fileName) {
var ODGOVOR = await PRENOS_PODATKOV.GetStringAsync(link);
File.WriteAllText(#"C:\Users\...\" + fileName + ".txt", ODGOVOR);
}
void function2() {
string originalText = File.ReadAllText(#"C:\Users\...\fileName.txt", Encoding.Default);
dynamic modifiedText = JsonConvert.DeserializeObject(originalText);
//then i then i read from the same text files and use some data from it..
}
You will have to close the file after editing it.
var myFile = File.Create(myPath);
//myPath = "C:\file.txt"
myFile.Close();
//closes the text file for eg. file.txt
//You can write your reading functions now..
After closing it you can again use it(for reading)
The issue is sometimes file locks don't get released immediately after they are closed.
You can try run a loop to read the file. Inside the loop put a try catch statement and if the file reads successfully break from the loop. Otherwise, wait a few milliseconds and try to read the file again:
string originalText = null;
while (true)
{
try
{
originalText = File.ReadAllText(#"C:\Users\...\fileName.txt", Encoding.Default);
break;
}
catch
{
System.Threading.Thread.Sleep(100);
}
}
after writing your text file, you should close it first before proceeding to your second function:
var myFile = File.Create(myPath);
//some other operations here like writing into the text file
myFile.Close(); //close text file
//call your 2nd function here
Just to elaborate:
public void Start() {
string filename = "myFile.txt";
CreateFile(filename); //call your create textfile method
ReadFile(filename); //call read file method
}
public void CreateFile(string filename) {
var myFile = File.Create(myPath); //create file
//some other operations here like writing into the text file
myFile.Close(); //close text file
}
public void ReadFile(string filename) {
string text;
var fileStream = new FileStream(filename, FileMode.Open,
FileAccess.Read); //open text file
//vvv read text file (or however you implement it like here vvv
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
text = streamReader.ReadToEnd();
}
//finally, close text file
fileStream.Close();
}
The point is, you have to close the FileStream after you are done with any operations with your file. You can do this via myFileStream.Close().
Moreover, File.Create(filename) returns a FileStream object which you can then Close().
Actually this is not a problem of closing/disposing the stream, File.WriteAllText and File.ReadAllText does that internally.
The issue is because a wrong use of the async/await pattern.
GET is async but never awaited, thus causing function1 to finish and move on to function2 before all content was actually written to the file.
The way it is written GET is not awaitable because it is async void which should never be used unless you're dealing with event or really know what you're doing.
So, either remove the use of async/await completely or be async all the way:
Change GET to be awaitable:
async Task GET(string link, string fileName)
await it in the now async function1:
async Task function1()
{
...
for (int x = 0; x < fileNames.Count; x++)
{
await GET(linki[x], fileNames[x]);
//System.Threading.Thread.Sleep(6000);
}
...
await function1 in the Elapsed event:
private async void tickTimera1(object source, ElapsedEventArgs e)
{
await function1();
function2();
}
Create a file and then close it. After can save data into that file.
I did as below.
if (!File.Exists(filePath))
{
File.Create(filePath).Close();
}
File.WriteAllText(filePath, saveDataString)
In one of the unit tests, I had to create a temp file and then remove it after, and I was getting the above error.
None of the answers worked.
Solution that worked was:
var path = $"temp.{extension}";
using (File.Create(path))
{
}
File.Delete(path);

Removing XML data through a DGV

I have a DataGridView which displays a list of rail cars and has several buttons for manipulating the list (Add, Edit, Delete, Save). The contents of the DGV come from an XML file and are saved back to the same file when the Save button is clicked. All functions of this form work perfectly with the exception of the Delete button. When I delete a rail car from the list and click Save, it takes the "deleted" row and re-appends it to the XML file in a very weird way (picture below).
Here is the code for the form (I'm only including the Save & Delete buttons and XML handling for ease of reading):
public partial class SimulatedTrainEditor : Form
{
//fileName and XML variables for serialization/deserialization
const string fileName = "SimulatedTrain1.xml";
XmlSerializer xml = new XmlSerializer(typeof(BindingList<SimulatedTrain>));
//Create BindingList object to hold XML data
public BindingList<SimulatedTrain> NewSimulatedTrain = new BindingList<SimulatedTrain>();
public bool WereChangesMade;
public SimulatedTrainEditor()
{
InitializeComponent();
LoadXML();
this.dataGridViewSimulatedTrainEditor.DataSource = NewSimulatedTrain;
this.dataGridViewSimulatedTrainEditor.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
this.dataGridViewSimulatedTrainEditor.AllowUserToAddRows = false;
this.WereChangesMade = false;
this.buttonSaveXML.Enabled = false;
}
public void LoadXML()
{
try
{
using (var fs = new FileStream(fileName, FileMode.Open))
{
NewSimulatedTrain = (BindingList<SimulatedTrain>)xml.Deserialize(fs);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message, ex);
}
}
private void buttonRemoveRailCar_Click(object sender, EventArgs e)
{
var currentRow = this.dataGridViewSimulatedTrainEditor.CurrentRow;
if (currentRow != null)
{
this.NewSimulatedTrain.RemoveAt(currentRow.Index);
this.WereChangesMade = true;
this.buttonSaveXML.Enabled = true;
}
}
private void buttonSaveXML_Click(object sender, EventArgs e)
{
//are there any changes?
if (WereChangesMade)
{
//save the file if changes
using (var fs = new FileStream(fileName, FileMode.OpenOrCreate))
{
xml.Serialize(fs, this.NewSimulatedTrain);
}
//Disable the SaveXML button when it's clicked to look for new edits after each save
this.buttonSaveXML.Enabled = false;
}
}
}
And here are screenshots of before and after I delete a row (this is just the bottom portion of the XML):
Before:
After (the red bit should be the end of the XML file):
You can see it tries to add another closing ArrayOfSimulatedTrain tag to the end after it throws in the row data that should have been deleted. I am still getting use to working with XML files, but in the few instances I've done this type of work before, I've never run into this particular issue.
Using FileStream in FileMode.OpenOrCreate mode does not wipe the content of file before writing.
Editing the XML changes the length of the content that will be written in the file. If the new XML is shorter, you will have some leftovers at the end of the file. From the MSDN :
If you overwrite a longer string (such as “This is a test of the OpenWrite method”) with a shorter string (such as “Second run”), the file will contain a mix of the strings (“Second runtest of the OpenWrite method”).
You need to change the FileMode of the stream to FileMode.Create to overwrite the whole file :
//save the file if changes
using (var fs = new FileStream(fileName, FileMode.Create))
{
xml.Serialize(fs, this.NewSimulatedTrain);
}

Categories