Add data to CSV if string is not found - c#

I have an application that updates data within a CSV. What I am trying to add is, if the "name" is not in the CSV, then add it. I have tried changing the while to an if/then, but that gave me no results, just a blank line within the CSV.
Code:
using (StreamReader reader = new StreamReader(path))
{
String line;
while ((line = reader.ReadLine()) != null)
{
if (line.Split(',')[0].Equals("newName"))
{
String[] split = line.Split(',');
split[1] = tPoints.ToString();
line = String.Join(",", split);
}
lines.Add(line);
}
}
using (StreamWriter writer = new StreamWriter(path))
{
foreach (String line in lines)
writer.WriteLine(line);
}
Current CSV Data:
name,734937
If item is NOT found, I am trying have it add a new row. So expected result would be something similar to below:
name,734937
newName,0

You can try something like this:
bool termFound = false;
string searchTerm = "newName";
var lines = new List<string>();
using (StreamReader reader = new StreamReader("input.csv"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
lines.Add(line);
if (line.Split(',')[0].Equals(searchTerm))
termFound = true;
}
}
using (StreamWriter writer = new StreamWriter("output.csv"))
{
foreach (string line in lines)
writer.WriteLine(line);
if(termFound == false)
writer.WriteLine($"{searchTerm},0");
}

Related

How do I delete all lines in text file below certain text?

I have a code which iterates through the entire text file searching for a specific text "[names]", and "tried" to delete all the lines below the text. I tried File.WriteAllText(INILoc, string.Empty);, but this just deletes everything in the entire text file. How do I make it so only all the lines below "[names]" gets deleted?
I have set up the iteration likes this :
string[] lines = File.ReadAllLines(INILoc);
bool containsSearchResul = false;
foreach (string line in lines)
{
if (containsSearchResul)
{
File.WriteAllText(INILoc, string.Empty);
}
if (line.Contains("[names]"))
{
containsSearchResul = true;
}
}
You need to store lines before "[names]" text into a string variable, and when condition (line.Contains("[names]")) satisfy then just break the loop and write string value into the same file.
Something like,
string[] lines = File.ReadAllLines(INILoc); //Considering INILoc is a string variable which contains file path.
StringBuilder newText = new StringBuilder();
bool containsSearchResul = false;
foreach (string line in lines)
{
newText.Append(line);
newText.Append(Environment.NewLine); //This will add \n after each line so all lines will be well formatted
//Adding line into newText before if condition check will add "name" into file
if (line.Contains("[names]"))
break;
}
File.WriteAllText(INILoc, newText.ToString());
//^^^^^^^ due to string.Empty it was storing empty string into file.
Note: If you are using StringBuilder class, then do not miss to add Using System.Text in your program
Use StreamReader as it will give you the best performance as you don't need to read the whole file. Swap 'PATH TO INPUT FILE' with your file path and the result will be stored at the path you provide for 'PATH TO OUTPUT FILE'.
using (var sr = new StreamReader("PATH TO INPUT FILE"))
{
using (var sw = new StreamWriter("PATH TO OUTPUT FILE"))
{
var line = sr.ReadLine();
while (line != null)
{
sw.WriteLine(line);
if (line.Contains("[names]"))
{
sw.Close();
sr.Close();
}
else
{
line = sr.ReadLine();
}
}
}
}
If you need to write to the same file:
var sb = new StringBuilder();
using (var sr = new StreamReader("PATH TO INPUT FILE"))
{
var line = sr.ReadLine();
while (line != null)
{
sb.AppendLine(line);
if (line.Contains("[names]"))
{
sr.Close();
}
else
{
line = sr.ReadLine();
}
}
}
File.WriteAllText("PATH TO INPUT FILE", sb.ToString());
Based on the requested code I have put together modifications.
string[] lines = File.ReadAllLines(INILoc);
//create a list to hold the lines
List<string> output = new List<string>();
//loop through each line
foreach (string line in lines)
{
//add current line to ouput.
output.Add(line);
//check to see if our line includes the searched text;
if (line.Contains("[names]"))
{
//output to the file and then exit loop causing all lines below this
//one to be skipped
File.WriteAllText(INILoc, output.ToArray());
break;
}
}
The problem with your code is that it delete all the lines before the [names], not after (more exactly, write only the lines after that text). Also, any time you rewrite all the file content, and so remove all previous wrote line. It'll work as follows:
string[] lines = File.ReadAllLines(INILoc);
using (StreamWriter writer = new StreamWriter(INILoc)) // https://learn.microsoft.com/en-us/dotnet/standard/io/how-to-write-text-to-a-file
{
bool containsSearchResul = false;
foreach (string line in lines)
{
if (!containsSearchResul)
{
writer.Write(INILoc, string.Empty);
}
if (line.Contains("[names]"))
{
containsSearchResul = true;
}
}
}
You have another, better option to do this with break:
string[] lines = File.ReadAllLines(INILoc);
using (StreamWriter writer = new StreamWriter(INILoc)) // https://learn.microsoft.com/en-us/dotnet/standard/io/how-to-write-text-to-a-file
{
foreach (string line in lines)
{
if (line.Contains("[names]"))
{
break;
}
writer.WriteLine(INILoc, string.Empty);
}
}
But you can do this in prefered, more-readable way, by using LINQ:
using System.Linq;
// ...
string[] lines = File.ReadAllLines(INILoc);
string[] linesTillNames = lines
.Take( // Take just N items from the array
Array.IndexOf(lines, "[names]") // Until the index of [names]
)
.ToArray();
File.WriteAllLines(INILoc, linesTillNames);
You can also use: WriteAllLines(string path, IEnumerable<string> contents) like this:
string[] lines = File.ReadAllLines(INILoc);
List<string> linesToWrite = new List<string>();
foreach(string line in lines)
{
linesToWrite.Add(line);
if (line.Contains("[names]")) break;
}
File.WriteAllLines(INILoc, linesToWrite);

CSV update/modification

Trying to override a single record of the following CSV:
PRODUCT,RECORD,ACCOUNT
100,200,300
using this code:
public static void UpdateCSV(string filePath, string stringToReplace, string updatedString)
{
string path = filePath;
List<string> lines = new List<string>();
if (File.Exists(path))
{
using (StreamReader reader = new StreamReader(path))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.Contains(","))
{
string[] split = line.Split(',');
if (split[1].Contains(stringToReplace))
{
split[1] = updatedString;
line = string.Join(",", split);
}
}
lines.Add(line);
}
}
using (StreamWriter writer = new StreamWriter(path, false))
{
foreach (string line in lines)
writer.WriteLine(line);
}
}
}
But invoking the following does not make a difference ('PRODUCT' does not change to 'MYPRODUCT'):
UpdateCSV(#"C:\Test.csv", "PRODUCT", "MYPRODUCT");
What's wrong here?

Comparing rows in a csv file

I am currently using the below code to compare two csv files with each other. This code gives an output with all the rows that are not the same. But when a row is missing everything after that row is not the same. How can I fix this? Thanks in advance.
List<string> lines = new List<string>();
List<string> lines2 = new List<string>();
try
{
StreamReader reader = new StreamReader(System.IO.File.OpenRead(file1));
StreamReader read = new StreamReader(System.IO.File.OpenRead(file2));
List<string> differences = new List<string>();
string line;
string line2;
int i = 0;
while ((line = reader.ReadLine()) != null && (line2 = read.ReadLine()) != null)
{
string[] split = line.Split(Convert.ToChar("\t"));
string[] split2 = line2.Split(Convert.ToChar("\t"));
if (split[i] != split2[i])
{
differences.Add("this row is not the same:, " + line);
}
else
{
}
i++;
}
System.IO.File.WriteAllLines(differencesFile, differences);
reader.Dispose();
read.Dispose();
}
catch
{
}
After help from a friend I made it work with this code:
List<string> file1 = new List<string>();
List<string> output = new List<string>();
string differencesFile = path;
File.WriteAllText(differencesFile, "");
try
{
StreamReader readFile1 = new StreamReader(System.IO.File.OpenRead(pathfile1));
string lineFile1;
while ((lineFile1 = readFile1.ReadLine()) != null)
{
bool match = false;
string[] colums = lineFile1.Split('\t');
StreamReader readFile2 = new StreamReader(System.IO.File.OpenRead(pathfile2));
string line2;
while ((line2 = readFile2.ReadLine()) != null)
{
string[] columsFile2 = line2.Split('\t');
if (colums[0] == columsFile2[0])
{
match = true;
}
}
if (!match)
{
output.Add(colums[0] + "; doesnt exist in pathfile2");
}
}
System.IO.File.WriteAllLines(differencesFile, output);
}
catch { }

Reading and changing a file

I'm reading a file using C# and class TextReader
TextReader reader = new StreamReader(stream);
string line;
while ((line = reader.ReadLine()) != null)
{
if (someCondition)
{
// I want to change "line" and save it into the file I'm reading from
}
}
In a code there is a question: how do I save a changed line to a file I'm reading from and continue reading?
Fast and dirty solution would be:
TextReader reader = new StreamReader(stream);
string line;
StringBuilder sb = new StringBuilder();
while ((line = reader.ReadLine()) != null)
{
if (someCondition)
{
//Change variable line as you wish.
}
sb.Append(line);
}
using (StreamWriter sw = new StreamWriter("filePath"))
{
sw.Write(sb.ToString());
}
or
TextReader reader = new StreamReader(stream);
string line;
String newLines[];
int index = 0;
while ((line = reader.ReadLine()) != null)
{
if (someCondition)
{
//Change variable line as you wish.
}
newLines[index] = line;
index++;
}
using (StreamWriter sw = new StreamWriter("filePath"))
{
foreach (string l in newLines)
{
sw.WriteLine(l);
}
}
If memory is too important you can try this too:
TextReader reader = new StreamReader(stream);
string line;
while ((line = reader.ReadLine()) != null)
{
if (someCondition)
{
//Change variable line as you wish.
}
using (StreamWriter sw = new StreamWriter("filePath"))
{
sw.WriteLine(line);
}
}
The easiest thing is to write a new file, then when finished, replace the old file with the new file. This way you only do writes in one file.
If you try to read/write in the same file, you will run into problems when the content you want to insert is not the exact same size as the content it is replacing.
There is nothing magic about text files. They are just a stream of bytes representing characters in a text encoding. There are no line concept in the file, just separators in the form of newline characters.
If the file is not too large, you should simply rewrite the whole file:
var lines = File.ReadAllLines(path)
.Where(l => someCondition);
File.WriteAllLines(path, lines);
A very simple solution
void Main()
{
var lines = File.ReadAllLines("D:\\temp\\file.txt");
for(int x = 0; x < lines.Length; x++)
{
// Of course this is an example of the condtion
// you should implement your checks
if(lines[x].Contains("CONDITION"))
{
lines[x] = lines[x].Replace("CONDITION", "CONDITION2");
}
}
File.WriteAllLines("D:\\temp\\file.txt", lines);
}
The drawback is the memory usage caused by the in memory lines, but, if we stay around 50MB, it should be handled effortlessly by modern PC.

Writing a specific line from one text file to other text file using c#

I Am using sharp develop. I am making a Win App using C# . I want my program check a text file named test in drive c: and find the line which contains "=" and then write this line to other newly created text file in drive c: .
Try this one-liner:
File.WriteAllLines(destinationFileName,
File.ReadAllLines(sourceFileName)
.Where(x => x.Contains("=")));
Here's another simple way using File.ReadLines, Linq's Where and File.AppendAllLines
var path1 = #"C:\test.txt";
var path2 = #"C:\test_out.txt";
var equalLines = File.ReadLines(path1)
.Where(l => l.Contains("="));
File.AppendAllLines(path2, equalLines.Take(1));
using(StreamWriter sw = new StreamWriter(#"C:\destinationFile.txt"))
{
StreamReader sr = new StreamReader(#"C:\sourceFile.txt");
string line = String.Empty;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("=")) { sw.WriteLine(line)); }
}
sr.Close();
}
Have you tried something?
Here are two ways to read a file:
Use static methods available in File class. ReadAllLines to be specific. This is good enough if you are dealing with small files. Next, once you have the array, just find the item with "=" using LINQ or by any other iteration method. Once you got the line, again use File class to create and write data to the file.
If you are dealing with large files, use Stream. Rest remains fairly same.
if (File.Exists(txtBaseAddress.Text))
{
StreamReader sr = new StreamReader(txtBaseAddress.Text);
string line;
string fileText = "";
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("="))
{
fileText += line;
}
}
sr.Close();
if (fileText != "")
{
try
{
StreamWriter sw = new StreamWriter(txtDestAddress.Text);
sw.Write(fileText);
sw.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
a bit edited Furqan's answer
using (StreamReader sr = new StreamReader(#"C:\Users\Username\Documents\a.txt"))
using (StreamWriter sw = new StreamWriter(#"C:\Users\Username\Documents\b.txt"))
{
int counter = 0;
string line = String.Empty;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("="))
{
sw.WriteLine(line);
if (++counter == 4)
{
sw.WriteLine();
counter = 0;
}
}
}
}

Categories

Resources