C# compare 2 files substrings for matches - c#

I am trying to find a way to compare some text in 2 files and if a match is found .
Here are examples of the files;
'File A'
ex1,TEXAS,24
ex2,MIAMI,78
ex3,ATLANTA,56
ex4,NY,90
...
'File B'
ex1,JHON,1110
exA,DAVID,1060
exB,CATHY,230
ex4,ROBERT,1200
...
Using my 2 example files, I want to search them both and find matches(
ex1,TEXAS,24
&
ex4,NY,90
)??!
Here is my try
private void button4_Click(object sender, EventArgs e)
{
string fileA, fileB, fileC;
fileA = textBox1.Text;
fileB = textBox2.Text;
fileC = "result.txt";
string alphaFilePath = fileA;
List<string> alphaFileContent = new List<string>();
using (FileStream fs = new FileStream(alphaFilePath, FileMode.Open))
using (StreamReader rdr = new StreamReader(fs))
{
while (!rdr.EndOfStream)
{
}
}
string betaFilePath = fileB;
StringBuilder sb = new StringBuilder();
using (FileStream fs = new FileStream(betaFilePath, FileMode.Open))
using (StreamReader rdr = new StreamReader(fs))
{
while (!rdr.EndOfStream)
{
string[] betaFileLine = rdr.ReadLine().Split(Convert.ToChar(","));
}
}
using (FileStream fs = new FileStream(fileC, FileMode.Create)){
using (StreamWriter writer = new StreamWriter(fs))
{
writer.Write(sb.ToString());
}
} foreach (var item in alphaFileContent)
{
if (item.StartsWith(betaFileLine[0]))
{
sb.AppendLine(String.Format("{0}", betaFileLine[0]));
}
}
}

You can get all the lines of a file into an array using File.ReadAllLines:
var alphaFileContents = File.ReadAllLines(fileA);
In your code, you are checking to see which items from file A StartWith the same text as an item from file B up to the first comma. We can get all the prefixes (line contents up to the first comma) from fileB by using string.Split(',')[0], which splits the string into an array on the comma character, and then returns the first item (at index 0):
var betaFilePrefixes = File.ReadAllLines(fileB).Select(line => line.Split(',')[0]);
Now, we can find the similar items by getting all items in fileA that start with an item from fileB. The Where clause below says, "where any alpha item starts with an item in betaFilePrefixes:
var similarItems = alphaFileContents
.Where(alpha => betaFilePrefixes.Any(beta => alpha.StartsWith(beta)));
Then, you can write all the matching lines to the results file using File.WriteAllLines:
File.WriteAllLines(fileC, similarItems);
So, to put it all together, you can do this:
private void button4_Click(object sender, EventArgs e)
{
var fileA = textBox1.Text;
var fileB = textBox2.Text;
var fileC = "result.txt";
// Read the alpha file contents into a list
var alphaFileContents = File.ReadAllLines(fileA);
// Read each line of the beta file, and select the first part
// (up to the first comma) into a list
var betaFilePrefixes = File.ReadAllLines(fileB).Select(line => line.Split(',')[0]);
// Get all alpha lines that start with an item in the beta list
var similarItems = alphaFileContents
.Where(alpha => betaFilePrefixes.Any(alpha.StartsWith));
// Write the lines to our result file
File.WriteAllLines(fileC, similarItems);
}

var matches = File.ReadAllText(fileA).Split(',')
.Intersect(File.ReadAllText(fileB).Split(','));

Related

How to link users file selection to a StringSplit

I'm trying to get the users chosen file to split into an array which is separated by , and /t.
The user can choose a file at the top of the code but how do I get their choice to split into an array lower down when they press the ValidateButton
The text file or ordered in this way
info,info,info,
info,info,info,
info,info,info,
If I can get them into an array then I can easily organises the data.
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = #"C:\"; // Start in C: drive
openFileDialog1.Title = "Browse Text Files";
openFileDialog1.RestoreDirectory = true;
openFileDialog1.DefaultExt = "txt"; // Extension of file is txt
openFileDialog1.Filter = "Text|*.txt||*.*"; //Only text files
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
FileNameBox.Text = openFileDialog1.FileName; // Chosen file name is displayed in text box
var fileStream = openFileDialog1.OpenFile();
using (StreamReader reader = new StreamReader(fileStream))
{
var fileContent = reader.ReadToEnd();
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
//This is the file path the user has chosen
}
public void ValidateButton_Click(object sender, EventArgs e)
{
//Call Multi line text box
//Call PROGRESS BAR_
int counter = 0;
string lines;
string Patient = lines;
string[] split = Patient.Split(new Char[] { ',', '\t' });
foreach (string s in split)
if (s.Trim() != "")
Console.WriteLine(s);
{
Console.WriteLine(lines);
counter++;
}
Console.WriteLine("There were {0} records.", counter);
Console.ReadKey();
}
List<string> temp = new List<string>();
string[] finalArray;
using (StreamReader reader = new StreamReader(fileStream))
{
// We read the file then we split it.
string lines = reader.ReadToEnd();
string[] splittedArray = lines.Split(',');
// We will check here if any of the strings is empty (or just whitespace).
foreach (string currentString in splittedArray)
{
if (currentString.Trim() != "")
{
// If the string is not empty then we add to our temporary list.
temp.Add(currentString);
}
}
// We have our splitted strings in temp List.
// If you need an array instead of List, you can use ToArray().
finalArray = temp.ToArray();
}

Using C# how can I split a text file into multiple files

How can I split a text file that contains ASCII code SOH and ETX into multiple files?
For exmaple the text file I have named 001234.txt contains the following content:
SOH{ABCDXZY}ETX
SOH{ABCDXZY}ETX
SOH{ABCDXZY}ETX
I would like to split the single text file into multiple text files for each ASCII code that starts with SOH and ends with ETX.
The single text file name should be splitted into 101234.txt , 111234.txt..etc and each contains a single content that starts with SOH and ends with ETX.
I appreciate any help.
using System.IO;
using System.Linq;
namespace ASCII_Split
{
class Program
{
static void Main(string[] args)
{
var txt = "";
const char soh = (char)1;
const char eox = (char)3;
var count = 1;
var pathToFile = #"‪‪C:\Temp\00599060.txt";
using (var sr = new StreamReader(pathToFile))
txt = sr.ReadToEnd();
while (txt.Contains(soh))
{
var outfil = Path.Combine(Path.GetDirectoryName(pathToFile), count.ToString("000"), "_fix.txt");
var eInd = txt.IndexOf(eox);
using (var sw = new StreamWriter(outfil, false))
{
sw.Write(txt.Substring(1, eInd - 1));
}
txt = txt.Substring(eInd + 1);
count++;
}
}
}
}
This should more or less do the trick:
//Read all text from file into a string
var fileContent = File.ReadAllText("001234.txt");
//split text into array according to a Regex pattern
var pattern = #"SOH*ETX";
var splitContent = Regex.Split(fileContent, pattern);
//counter for file names
var counter = 10;
foreach(var content in splitContent)
{
//create file and use stream to write to it
using (var stream = File.Create($"{counter++}1234.txt"))
{
var contentAsBytes = new UTF8Encoding(true).GetBytes(content);
stream.Write(contentAsBytes, 0, contentAsBytes.Length);
}
}
Provided by SOH and ETX you mean the respective control characters, this here should get you on your way:
var txt = "";
const char soh = (char) 1;
const char eox = (char) 3;
var count = 1;
var pathToFile = #"C:\00_Projects_temp\test.txt";
using (var sr = new StreamReader(pathToFile))
txt = sr.ReadToEnd();
while (txt.Contains(soh))
{
var outfil = Path.Combine(Path.GetDirectoryName(pathToFile), count.ToString("000"), "_test.txt");
var eInd = txt.IndexOf(eox);
using (var sw = new StreamWriter(outfil, false))
{
sw.Write(txt.Substring(1, eInd - 1));
}
txt = txt.Substring(eInd + 1);
count++;
}
Thank you LocEngineer the program works, I did little change to concatonate the filename with the counter using "+" instead of ",".
using System.IO;
using System.Linq;
namespace ASCII_Split
{
class Program
{
static void Main(string[] args)
{
var txt = "";
const char soh = (char)1;
const char eox = (char)3;
var count = 1;
var pathToFile = #"C:\Temp\00599060.txt";
using (var sr = new StreamReader (pathToFile))
txt = sr.ReadToEnd();
if (txt.IndexOf(soh) != txt.LastIndexOf(soh))
{
while (txt.Contains(soh))
{
var outfil = Path.Combine(Path.GetDirectoryName(pathToFile), count.ToString("00") + Path.GetFileName(pathToFile));
var eInd = txt.IndexOf(eox);
using (var sw = new StreamWriter(outfil, false))
{
sw.Write(txt.Substring(1, eInd - 1));
}
txt = txt.Substring(eInd + 1);
count++;
}
File.Move((pathToFile), (pathToFile) + ".org");
}
}
}
}

C# Change specific lines in file

I have a text file containing some information that I want to edit. The file looks something like this:
id: 31
name: Anna
profession: Doctor
I can read that entry with a StreamReader, and present it in my application. I then want the user to be able to change the name and profession of an entry, so I'd like to edit these specific rows to the new values, while keeping id intact (in my real code, there's not just a few rows, but a lot of rows where only some should be changed). So, for example, I want the file, at the end of my operation, to look like this.
id: 31
name: Emma
profession: Programmer
However, I also have to take into account that sometimes the rows don't exist beforehand. For example, before editing Anna to Emma, it's not certain that she had a profession, the file could have looked like this:
id: 31
name: Anna
And in that case, I want to add the line profession: Programmerto the end there.
I tried using a FileStreamwith ReadWrite access, that I give to a StreamReader and a StreamWriter, but then I found no way of changing or replacing a line of text, only reading it and writing a new identical line while keeping the old.
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite))
using (StreamReader reader = new StreamReader(fileStream))
using (StreamWriter writer = new StreamWriter(fileStream))
{
bool idExists = false;
bool nameExists = false;
bool tagsExist = false;
string line;
while((line = reader.ReadLine()) != null)
{
if (line.StartsWith("id:"))
idExists = true;
else if (line.StartsWith("name:"))
{
nameExists = true;
line = $"name: {entryToSave.Name}";
writer.WriteLine(line); // Will write an additional line and not replace
}
else if (line.StartsWith("profession:"))
{
professionExists = true;
line = $"profession: {entryToSave.Profession}";
writer.WriteLine(line); // Will write an additional line and not replace
}
}
if (!idExists)
writer.WriteLine($"id: {generatedId}");
if (!nameExists)
writer.WriteLine($"name: {entryToSave.Name}");
if (!professionExists)
writer.WriteLine($"profession: {entryToSave.Profession}");
}
I also tried using File.ReadAllLines, loop through the lines, and then write back all the lines to the file, only modifying the lines that were to be modified. However, I don't have access to the file through File.WriteAllLines for some reason that I don't understand, as a StreamWriter has access. Code:
var previousData = File.ReadAllLines(filePath);
var newData = new List<string>();
bool idExists = false;
bool nameExists = false;
bool professionExists = false;
for (int i = 0; i < previousData.Length; i++)
{
var line = previousData[i];
if (line.StartsWith("id:")
idExists = true;
else if (line.StartsWith("name:")
{
nameExists = true;
line = $"name: {entryToSave.Name}";
}
else if (line.StartsWith("profession:"))
{
professionExists = true;
line = $"profession: {entryToSave.Profession}";
}
newData.Add(line);
}
if (!idExists)
newData.Add($"id: {generatedId}");
if (!nameExists)
newData.Add($"name: {entryToSave.Name}");
if (!professionExists)
newData.Add($"profession: {entryToSave.Profession}");
File.WriteAllLines(filePath, newData.ToArray()); // Access denied
How is this most easily achieved, without file streams interfering with each other?
If you've already presented the data to the user in entries, enabling the user to edit name and profession, you could just read the file, get the ID and fill the remainder of the file with the value of the entries. The following is an example console application.
static void Main(string[] args)
{
var filePath = "test.txt";
// Simulated input from user
// these should come from entries in the application?
var name = "Foo";
var profession = "Bar";
var personData = new PersonData(); // class declared below
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite))
using (StreamReader reader = new StreamReader(fileStream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.StartsWith("id:"))
personData.ID = line;
}
} // Now reader and filestream is closed, file is available again.
// You don't specify what you would like to happen if personData.ID is null,
// so I make an assumption the generatedId is what you'd like to use.
if (string.IsNullOrWhiteSpace(personData.ID)
personData.ID = $"id: {generatedId}";
// Add the data from the entries
personData.Name = $"name: {name}";
personData.Profession = $"profession: {profession}";
File.Delete(filePath); // remove the file
using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
using (StreamWriter writer = new StreamWriter(fileStream))
{
writer.WriteLine(personData.ID);
writer.WriteLine(personData.Name);
writer.WriteLine(personData.Profession);
}
}
private class PersonData
{
public string ID { get; set; }
public string Name { get; set; }
public string Profession { get; set; }
}
Now you just have to find out how to get access to the file if you're having permission problems.

Csharp substring text and add it to list

I have file.txt like:
EDIT: I didn't wrote but this is important i guess- In file.txt there can be others lines!
folder=c:\user;c:\test;c:\something;
I need to add one path like one list item (List<string> Folders).
So my List should looks like:
Folders[0] = c:\user
Folders[1] = c:\test
etc. (without text "folder=" which starts line in file.txt and ";" which means end of path).
file can contain much more paths.
I did something like this:
using (FileStream fss = new FileStream(path, FileMode.Open))
{
using (StreamReader sr = new StreamReader(fss))
{
while (sr.EndOfStream == false)
{
string line = sr.ReadLine();
if(line.StartsWith("folders"))
{
int index = line.IndexOf("=");
int index1 = line.IndexOf(";");
string folder = line.Substring(index + 1, index1 - (index + 1));
Folders.Add(folder);
Now in List Folders i have first path but what now? I can't go ahead :(
using(var sr = new StreamReader(path))
{
var folders = sr.ReadToEnd()
.Split(new char[]{';','\n','\r'}, StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.Replace("folder=",""))
.ToArray();
Folders.AddRange(folders);
}
You can try following code, using File.ReadAllText
string Filepath = "c:\abc.txt";
string filecontent = File.ReadAllText(Filepath);
string startingString = "=";
var startIndex = filecontent.IndexOf(startingString);
filecontent = filecontent.Substring(startIndex + 1, filecontent.Length - startIndex - 2);
List<String> folders = filecontent.Split(';').ToList();
Here's a simple example:
List<String> Folders = new List<string>();
private void button1_Click(object sender, EventArgs e)
{
string path = #"C:\Users\mikes\Documents\SomeFile.txt";
string folderTag = "folder=";
using (FileStream fss = new FileStream(path, FileMode.Open))
{
using (StreamReader sr = new StreamReader(fss))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
if (line.StartsWith(folderTag))
{
line = line.Substring(folderTag.Length); // remove the folderTag from the beginning
Folders.AddRange(line.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries));
}
}
}
}
foreach(string folder in Folders)
{
Console.WriteLine(folder);
}
}
I'd use this approach if you're going to read line by line, and do something else based on what each line starts with. In that case you could add different else if(...) blocks:
if (line.StartsWith(folderTag))
{
line = line.Substring(folderTag.Length); // remove the folderTag from the beginning
Folders.AddRange(line.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries));
}
else if(line.StartsWith("parameters="))
{
// do something different with a line starting with "parameters="
}
else if (line.StartsWith("unicorns="))
{
// do something else different with a line starting with "unicorns="
}

C# CSV file still open when appending

I'm trying to allow the user to add another entry to the CSV file my program is building. It is building it out of a database like this:
public void CreateCsvFile()
{
var filepath = #"F:\A2 Computing\C# Programming Project\ScheduleFile.csv";
var ListGather = new PaceCalculator();
var records =
from record in ListGather.NameGain()
.Zip(ListGather.PaceGain(),
(a, b) => new { Name = a, Pace = b })
group record.Pace by record.Name into grs
select String.Format("{0},{1}", grs.Key, grs.Average()); //reduces the list of integers down to a single double value by computing the average.
File.WriteAllLines(filepath, records);
}
I then am calling it into a datagridview like this:
private void button2_Click(object sender, EventArgs e)
{
CreateExtFile CsvCreate = new CreateExtFile();
CsvCreate.CreateCsvFile();
return;
}
private void LoadAthletes()
{
string delimiter = ",";
string tableName = "Schedule Table";
string fileName = #"F:\A2 Computing\C# Programming Project\ScheduleFile.csv";
DataSet dataset = new DataSet();
StreamReader sr = new StreamReader(fileName);
dataset.Tables.Add(tableName);
dataset.Tables[tableName].Columns.Add("Athlete Name");
dataset.Tables[tableName].Columns.Add("Pace Per Mile");
string allData = sr.ReadToEnd();
string[] rows = allData.Split("\r".ToCharArray());
foreach (string r in rows)
{
string[] items = r.Split(delimiter.ToCharArray());
dataset.Tables[tableName].Rows.Add(items);
}
this.dataGridView1.DataSource = dataset.Tables[0].DefaultView;
}
A button opens a window which contains fields to add a new entry to the csv file. This is how I am doing this:
private void AddToScheduleBtn_Click(object sender, EventArgs e)
{
string FileName = #"F:\A2 Computing\C# Programming Project\ScheduleFile.csv";
string AthleteDetails = textBox1.Text + "," + textBox2.Text;
File.AppendAllText(FileName, AthleteDetails);
AddToSchedule.ActiveForm.Close();
}
Although this works once, When I try and add another entry to my csv file again it says it is open in another process and the program crashes. When the data first appears in my datagridview, there is an empty row at the bottom which there shouldn't be. What is the best way of allowing me to re-use the process so I can append to the file more than once?
I think your line,
StreamReader sr = new StreamReader(fileName);
has the file opened. You want to do the following:
string allData = sr.ReadToEnd();
sr.Close();
sr.Dispose();
I didn't build your code, but this error is usually raised when the file reader was not closed :)
You should add sr.close() to your LoadAthletes method or implement the using for an automatic closing:
using (StreamReader sr = new StreamReader(fileName))
{
allData = sr.ReadToEnd();
}
Or use the following method :
allData = File.ReadAllText(fileName);
Hope this Help
For more information see this question do-i-need-to-explicitly-close-the-streamreader-in-c-sharp-when-using-it-to-load

Categories

Resources