Check if item is found in text file - c#

How can I check if a text file contains an item from a listbox. To stop saving duplicates. I'm not sure what I'd add to this. This is called on a button click event. For example, if a duplicate was found, I could show MessageBox.Show ("duplicate error");
using (StreamWriter writer = new StreamWriter("test.txt", true))
{
foreach (object item in listBox2.Items)
{
writer.WriteLine(item.ToString());
}
}

Before writing to "test.txt", enumerate its contents:
var fileLines = File.ReadAllLines("test.txt");
List<string> fileItems = new List<string>(fileLines);
Then before you write each item, check to see if the list contains it:
using (StreamWriter writer = new StreamWriter("test.txt", true))
{
foreach (object item in listBox2.Items)
{
if (fileItems.Contains(item))
// Do something, break, etc.
else
writer.WriteLine(item.ToString());
}
}
Edit:
Per suggestions, you can use a HashSet instead of a List for performance, as it can only contain unique values.
Another improvement may be to check if any duplicates exist before writing anything to the file. I've done that in the example below in a LINQ statement:
var fileLines = File.ReadAllLines("test.txt");
HashSet<string> fileItems = new HashSet<string>(fileLines);
using (StreamWriter writer = new StreamWriter("test.txt", true))
{
bool duplicateFound = fileItems.Any(fi => listBox1.Items.Cast<string>().Any(i => i == fi));
if (duplicateFound)
MessageBox.Show("Duplicate items found.");
else
foreach (object item in listBox1.Items)
writer.WriteLine(item.ToString());
}
Edit 2:
As #Servy suggested, the listbox could contain duplicates, which should also be taken into consideration. Additionally, my HashSet implementation was sub-par. So in this third example, I am first checking if the listbox contains duplicates, then if any of the listbox items are already in the file. The usage of HashSet is more performant as well because I am not iterating it.
var fileLines = File.ReadAllLines("test.txt");
HashSet<string> fileItems = new HashSet<string>(fileLines);
List<string> duplicateListboxItems = listBox1.Items.Cast<string>().GroupBy(l => l).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
if (duplicateListboxItems.Count > 0)
{
MessageBox.Show("The listbox contains duplicate entries.");
return;
}
bool duplicateFound = false;
List<string> outputItems = new List<string>();
foreach (string item in listBox1.Items)
{
if (fileItems.Contains(item))
{
MessageBox.Show(String.Format("The file has a duplicate: {0}", item));
duplicateFound = true;
break;
}
outputItems.Add(item);
}
if (duplicateFound)
return;
using (StreamWriter writer = new StreamWriter("test.txt", true))
{
foreach (string s in outputItems)
writer.WriteLine(s);
}

string filePath = "test.txt";
var existingLines = new HashSet<string>(File.ReadAllLines(filePath));
var linesToWrite = new List<string>();
foreach (string item in listBox2.Items)
{
if (existingLines.Add(item))
{
linesToWrite.Add(item);
}
else
{
//this is a duplicate!!!
}
}
File.AppendAllLines(filePath, linesToWrite);

Related

How to read and separate segments of a txt file?

I have a txt file, that has headers and then 3 columns of values (i.e)
Description=null
area = 100
1,2,3
1,2,4
2,1,5 ...
... 1,2,1//(these are the values that I need in one list)
Then another segment
Description=null
area = 10
1,2,3
1,2,4
2,1,5 ...
... 1,2,1//(these are the values that I need in one list).
In fact I just need one list per "Table" of values, the values always are in 3 columns but, there are n segments, any idea?
Thanks!
List<double> VMM40xyz = new List<double>();
foreach (var item in VMM40blocklines)
{
if (item.Contains(','))
{
VMM40xyz.AddRange(item.Split(',').Select(double.Parse).ToList());
}
}
I tried this, but it just work with the values in just one big list.
It looks like you want your data to end up in a format like this:
public class SetOfData //Feel free to name these parts better.
{
public string Description = "";
public string Area = "";
public List<double> Data = new List<double>();
}
...stored somewhere in...
List<SetOfData> finalData = new List<SetOfData>();
So, here's how I'd read that in:
public static List<SetOfData> ReadCustomFile(string Filename)
{
if (!File.Exists(Filename))
{
throw new FileNotFoundException($"{Filename} does not exist.");
}
List<SetOfData> returnData = new List<SetOfData>();
SetOfData currentDataSet = null;
using (FileStream fs = new FileStream(Filename, FileMode.Open))
{
using (StreamReader reader = new StreamReader(fs))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
//This will start a new object on every 'Description' line.
if (line.Contains("Description="))
{
//Save off the old data set if there is one.
if (currentDataSet != null)
returnData.Add(currentDataSet);
currentDataSet = new SetOfData();
//Now, to make sure there is something after "Description=" and to set the Description if there is.
//Your example data used "null" here, which this will take literally to be a string containing the letters "null". You can check the contents of parts[1] inside the if block to change this.
string[] parts = line.Split('=');
if (parts.Length > 1)
currentDataSet.Description = parts[1].Trim();
}
else if (line.Contains("area = "))
{
//Just in case your file didn't start with a "Description" line for some reason.
if (currentDataSet == null)
currentDataSet = new SetOfData();
//And then we do some string splitting like we did for Description.
string[] parts = line.Split('=');
if (parts.Length > 1)
currentDataSet.Area = parts[1].Trim();
}
else
{
//Just in case your file didn't start with a "Description" line for some reason.
if (currentDataSet == null)
currentDataSet = new SetOfData();
string[] parts = line.Split(',');
foreach (string part in parts)
{
if (double.TryParse(part, out double number))
{
currentDataSet.Data.Add(number);
}
}
}
}
//Make sure to add the last set.
returnData.Add(currentDataSet);
}
}
return returnData;
}

Refresh a listbox to display new values

This is a newb question so I'm sorry.
I'm filling out my text box with values Im grabbing on line and passing them to the listbox like so:
// textBox1.Text = test.ToString();
string[] names = result.Split('|');
foreach (string name in names)
{
listBox1.Items.Add(name);
}
However I'm trying to click on a folder and have the files displayed from there be shown in my listbox1. THis is what I've tried:
using (var testy = new WebClient())
{
test = testy.DownloadString("http://server.foo.com/images/getDirectoryList.php?dir=test_folder");
string[] names1 = test.Split('|');
foreach (string name in names1)
{
listBox1.Items.Clear();
listBox1.Items.Add(name);
listBox1.Update();
}
}
But all that happens is that my listbox empties and doesn't get refreshed. How can I achieve what I want to do?
before you do anything else remove the clear and update from the foreach
listBox1.Items.Clear();
foreach (string name in names1)
{
listBox1.Items.Add(name);
}
listBox1.Update();
your lines
foreach (string name in names1)
{
listBox1.Items.Clear();
listBox1.Items.Add(name);
listBox1.Update();
}
makes it that for every string you are removing ever other item in the list.
i'm pretty sure that's not what you want
Use a BindingSource
BindingSource bs = new BindingSource();
List<string> names1 = new List();
bs.DataSource = names1;
comboBox.DataSource = bs;
using (var testy = new WebClient())
{
test = testy.DownloadString("http://server.foo.com/images/getDirectoryList.php?dir=test_folder");
names1.AddRange(test.Split('|'));
bs.ResetBindings(false);
}
The BindingSource will take care of everything for you.

ListView adding items with subitems

I'm trying to read a file line by line, which works perfectly but I want to seperate the results I get into subitems in the listview.
I am also searching for all .jar files in the folder so I can use those as the name (first column). The second column needs to have the "version", the third column the "author" and the fourth column the "description".
Here's one of the text files I receive from within the jar files:
name: AFK
main: com.github.alesvojta.AFK.AFK
version: 2.0.5
author: Ales Vojta / schneckk
description: Provides AFK messages
website: http://dev.bukkit.org/server-mods/afk/
commands:
afk:
description: Provides AFK message when player types /afk.
usage: /<command>
this is the code I have right now:
private List<string> GetInstalledPlugins()
{
List<string> list = new List<string>();
lvInstalledPlugins.Items.Clear();
if (!Directory.Exists(Environment.CurrentDirectory + "\\plugins"))
{
Directory.CreateDirectory(Environment.CurrentDirectory + "\\plugins");
DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\plugins");
FileInfo[] fileInfo = di.GetFiles("*.jar");
foreach (var info in fileInfo)
{
//lvInstalledPlugins.Items.Add(info.Name);
list.Add(info.Name);
}
}
else
{
DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\plugins");
FileInfo[] fileInfo = di.GetFiles("*.jar");
foreach (var info in fileInfo)
{
//lvInstalledPlugins.Items.Add(info.Name);
list.Add(info.Name);
}
}
return list;
}
private void test(IEnumerable<string> list)
{
List<ListViewItem> PluginList = new List<ListViewItem>();
var items = new string[4];
try
{
foreach (var ListItem in list)
{
Console.WriteLine(ListItem);
var name = Environment.CurrentDirectory + "\\plugins\\" + ListItem;
var zip = new ZipInputStream(File.OpenRead(name));
var filestream = new FileStream(name, FileMode.Open, FileAccess.Read);
var zipfile = new ZipFile(filestream);
ZipEntry item;
while ((item = zip.GetNextEntry()) != null)
{
if (item.Name == "plugin.yml")
{
using (var s = new StreamReader(zipfile.GetInputStream(item)))
{
string line;
while ((line = s.ReadLine()) != null)
{
if (line.Contains("name"))
{
items[0] = line;
}
if (line.Contains("version"))
{
items[1] = line;
}
if (line.Contains("author"))
{
items[2] = line;
}
if (line.Contains("description"))
{
items[3] = line;
}
try
{
var lvitem = new ListViewItem(items);
lvitem.Name = items[0];
lvitem.Text = items[0];
lvitem.SubItems.Add(items[1]);
lvitem.SubItems.Add(items[2]);
lvitem.SubItems.Add(items[3]);
PluginList.Add(lvitem);
}
catch (Exception)
{
}
}
lvInstalledPlugins.Items.AddRange(PluginList.ToArray());
}
}
}
}
This doesn't seem to work :/, any ideas? I've been working on this for the whole day and can't seem to get it to work :(.
Not exactly sure of your question, but going by the title, the answer to the question below may provide some assistance.
C# listView, how do I add items to columns 2, 3 and 4 etc?

how to read text file and count the same names

I wanna create text file containing one name on each line. Compute the number of times any name occurs. Output one line for each name in file and on each line print the number of occurrences followed by name.
I can open the file by using this code
private void button1_Click(object sender, EventArgs e)
{
using (OpenFileDialog dlgOpen = new OpenFileDialog())
{
try
{
// Available file extensions
openFileDialog1.Filter = "All files(*.*)|*.*";
// Initial directory
openFileDialog1.InitialDirectory = "D:";
// OpenFileDialog title
openFileDialog1.Title = "Open";
// Show OpenFileDialog box
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// Create new StreamReader
StreamReader sr = new StreamReader(openFileDialog1.FileName, Encoding.Default);
// Get all text from the file
string str = sr.ReadToEnd();
// Close the StreamReader
sr.Close();
// Show the text in the rich textbox rtbMain
}
}
catch (Exception errorMsg)
{
MessageBox.Show(errorMsg.Message);
}
}
}
But what I want is to use the same button to read and display it in groupbox.
As this is homework, I am not going to give you code, but hopefully enough info to point you in the right direction.
I suggest you use File.ReadAllLines to read the file into an array of strings, each item in the array is one line in the file. This means you do not have to split the file contents up yourself. Then you can loop over the string array, and add each line to a Dictionary, where the key is the line read from the file, and the value is the number of occurrences. You need to check whether the key is already in the Dictionary - if not add it with a count of 1, otherwise update the existing count (+1). After that loop, have a second loop which loops over the Dictionary contents, updating your textbox with the names and their counts.
(assuming this is a homework) I used File.ReadAllLine and Dictionary<TKey, TValue>:
var nameCount = new Dictionary<string, int>();
foreach (String s in File.ReadAllLines("filename"))
{
if (nameCount.ContainsKey(s))
{
nameCount[s] = nameCount[s] + 1;
}
else
{
nameCount.Add(s, 1);
}
}
// and printing
foreach (var pair in nameCount)
{
Console.WriteLine("{0} count:{1}", pair.Key, pair.Value);
}
You can do that using Linq, without having to increment a int variable. To finaly have a dictionary containing names and counts
string names = sr.ReadAllLines();
Dictionary<string, int> namesAndCount = new Dictionary<string, int>();
foreach(var name in names)
{
if(namesAndCount.ContainsKey(name))
continue;
var count = (from n in names
where n == name
select n).Count();
namesAndCount.Add(name, count);
}
Okay, a function like this will build you distinct names with counts.
private static IDictionary<string, int> ParseNameFile(string filename)
{
var names = new Dictionary<string, int>();
using (var reader = new StreamReader(filename))
{
var line = reader.ReadLine();
while (line != null)
{
if (names.ContainsKey(line))
{
names[line]++;
}
else
{
names.Add(line, 1);
}
line = reader.ReadLine();
}
}
}
Or you could do somthing flash with linq and readAllLines.
private static IDictionary<string, int> ParseNameFile(string filename)
{
return File.ReadAllLines(filename)
.OrderBy(n => n)
.GroupBy(n => n)
.ToDictionary(g => g.Key, g => g.Count);
}
The first option does have the adavantage of not loading the whole file into memory.
As for outputting the information,
var output = new StringBuilder();
foreach (valuePair in ParseNameFile(openFileDialog1.FileName))
{
output.AppendFormat("{0} {1}\n", valuePair.Key, valuePair.Value);
}
Then you ToString() on output to put the data anywhere you want. If there will very many rows, a StreamWriter approach would be preferred.
Similar question has been asked before:
A method to count occurrences in a list
In my opinion using LINQ query is a good option.
string[] file = File.ReadAllLines(openFileDialog1.FileName, Encoding.Default);
IEnumerable<string> groupQuery =
from name in file
group name by name into g
orderby g.Key
select g;
foreach (var g in groupQuery)
{
MessageBox.Show(g.Count() + " " + g.Key);
}

How to make a listView item checked after comparing some string?

Can anyone help me to solve my little trouble?
I'm writing an app to work with text files. And I have GUI which contains a listView with checkboxes for each item.
I've created 2 arrays:
1st for items in listView and 2nd for all lines in a text file
string[] itemInList = new string[] { listView1.Items.ToString()
string[] lineInHosts = File.ReadAllLines(C:\Test.txt).ToArray<string>();
The idea is to compare all lines in "C:\Test.txt" file and all items in the listView.
If there will be a match, I want this item to be item.Checked = true;
PS: I've tried this -
foreach (var item in itemInList)
{
foreach (var l in lineInHosts)
{
string itemName;
ListViewItem foundItem;
if (item == l)
{
itemName = item.ToString();
foundItem = listView1.FindItemWithText(itemName);
foundItem.Checked = true;
}
}
}
but it doesn't work.
First line should be different and the second loop is not efficient:
string[] itemInList = listView1.Items.OfType<ListViewItem>( ).Select( p => p.Text ).ToArray( );
string[] lineInHosts = File.ReadAllLines( #"C:\Test.txt" ).ToArray<string>( );
string itemName;
ListViewItem foundItem;
foreach ( var item in itemInList )
{
if (lineInHosts.Contains(item))
{
itemName = item.ToString( );
foundItem = listView1.FindItemWithText( itemName );
foundItem.Checked = true;
}
}
This line looks suspicious :)
string[] itemInList = new string[] { listView1.Items.ToString()
There will be only one item in itemInList, and it will be called like your type.
Instead use:
string[] itemInList = listView1.Items.Select(x => x.ToString()).ToArray();
Try below answer, hope it will save someone's time
foreach (var room in customerRooms)
{
lstViewRooms.Items.Cast<ListViewItem>().Where(x =>.Text.Contains(room.Room.ToString())).FirstOrDefault().Selected = true;
}

Categories

Resources