I've written this console application to search for a particular string from a file and see if its present or not.. But i want to open only the file in the main program. And include 10different threads to find 10 different words simultaneously.. I tried using the thread but i didnt get it right.. How do i do it? could someone help me with the code? This is my program..
class Program
{
static void Main(string[] args)
{
Thread T = new Thread(Finding);
T.Start();
using (System.IO.StreamReader Reader = new System.IO.StreamReader("C://myfile2.txt"))
{
StringBuilder Sb = new StringBuilder();
string fileContent = Reader.ReadToEnd();
if (fileContent.Contains("and"))
{
Console.WriteLine("It is Present");
}
else
{
Console.WriteLine("It is not Present");
}
Console.ReadLine();
}
}
static void Finding()
{
if (fileContent.Contains("hello"))
{
Console.WriteLine("It is Present");
}
else
{
Console.WriteLine("It is not Present");
}
}
}
var text = File.ReadAllText("somePath");
foreach (var word in new[]{"word1", "word2", "word3"})
{
var w = word;
new Thread(() => Console.WriteLine("{0}: {1}",
w,
text.Contains(w) ? "Yes" : "No")).Start();
}
You should know that string can't contain infinite characters, so if the content is too big for a string, you could use File.ReadAllLines("path") into "lines" instead of File.ReadAllText("path") into "text" and replace
text.Contains(w)
with
lines.Any(l => l.Contains(w))
You could also do something sophisticated using File.ReadLines() to avoid reading all lines when not necessary, if you believe that all words are likely to be found.
Related
I'm coding a game for a university project similar to Subway Surfers. I have everything working precisely but my problem comes in a bookmarks option I coded.
When you lose in the game you have to enter a name and this is written and saved on a text file in the format <int score> <string name>, for example:
11245 Lucas
10123 Marco
2394 Ricky
So then in the menu of the game you can select bookmarks and the text file is read and shown on the screen one score under the other with the name that was written in each game.
Now my problem is that I want the bookmarks to be ordered, with the highest on top, but I do not know how I can do that as I have an int and a string in each line and they are related therefore I can't have one file for the scores and one file for the names as therefore when I order the scores I lost the info regarding who achieved each score.
What can I do to solve this?
EDIT:
I'm adding the part of the code related to my question.
This is the method that shows the bookmarks
static void ReadBookmark()
{
Console.Clear();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("BOOKMARKS");
string myfile = #"bookmarks.txt";
if (File.Exists(myfile) == false)
{
Console.WriteLine("\n");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("NO BOOKMARKS. PLAY SOME GAMES!");
Console.Write("\nPRESS A KEY TO RETURN...");
Console.ReadKey();
}
else
{
Console.WriteLine("\n");
Console.ForegroundColor = ConsoleColor.Green;
using (StreamReader sr = File.OpenText(myfile))
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
Console.WriteLine($"\t{s}");
}
}
Console.ForegroundColor = ConsoleColor.White;
Console.Write("\n\nPRESS A KEY TO RETURN...");
Console.ReadKey();
}
}
And here is the code where the name and score are written on the file.
public void SaveBookmark(int score, string name)
{
string myfile = #"bookmarks.txt";
using (StreamWriter sw = File.AppendText(myfile))
{
sw.WriteLine($"{score} {name}");
}
}
You can split each line on whitespace and then use int.Parse to get the numeric value of the first part, and then OrderByDescending using that value:
var orderedLines = File.ReadLines(myfile)
.OrderByDescending(line => int.Parse(line.Split()[0]))
.ToList();
Full example of what to do safely, finished before you posted your code.
This will allow the names to have a space in them.
public List<ScoreItem> GetScores()
{
var scoreList = new List<ScoreItem>();
using (var fs = File.OpenRead("myPath"))
using (var sr = new StreamReader(fs))
{
while (!sr.EndOfStream)
{
var line = sr.ReadLine();
if (string.IsNullOrWhiteSpace(line)) continue;
var scoreMatch = Regex.Match(line, #"\A\d*");
if (!scoreMatch.Success)
throw new Exception($"Failed to parse score from line [{line}].");
var nameMatch = Regex.Match(line, #"(?<!\A\d*).*\Z");
if (!nameMatch.Success)
throw new Exception($"Failed to parse name from line [{line}].");
if (!int.TryParse(scoreMatch.Value, out var score))
throw new Exception($"Failed to cast score to a number from line [{line}].");
scoreList.Add(new ScoreItem {Name = nameMatch.Value, Score = score});
}
return scoreList.OrderByDescending(s => s.Score).ToList();
}
}
public class ScoreItem
{
public string Name { get; set; }
public int Score { get; set; }
}
in this button click event I am trying to count strings from text file that are the same as in textboxes, then display number of them in label. My problem is that I have no idea how to count them-I'm talking about code inside if-statement. I would really appreciate any help.
private void btnCalculate_Click(object sender, EventArgs e)
{
string openFileName;
using (OpenFileDialog ofd = new OpenFileDialog())
{
if (ofd.ShowDialog() != DialogResult.OK)
{
MessageBox.Show("You did not select OK");
return;
}
openFileName = ofd.FileName;
}
FileStream fs = null;
StreamReader sr = null;
try
{
fs = new FileStream("x", FileMode.Open, FileAccess.Read);
fs.Seek(0, SeekOrigin.Begin);
sr = new StreamReader(fs);
string s = sr.ReadLine();
while (s != null)
{
s = sr.ReadLine();
}
if(s.Contains(tbFirstClub.Text))
{
s.Count = lblResult1.Text; //problem is here
}
else if(s.Contains(tbSecondClub.Text))
{
s.Count = lblResult2.Text; //problem is here
}
}
catch (IOException)
{
MessageBox.Show("Error reading file");
}
catch (Exception)
{
MessageBox.Show("Something went wrong");
}
finally
{
if (sr != null)
{
sr.Close();
}
}
}
Thanks in advance.
s.Count = lblResult1.Text; //problem is here
wait...you are saying here..
you have a variable (s)
and you access its property (Count)
and then set it to the label text(lblResult1.Text)
is that what you're trying to do? because the reverse seems more likely
Using LINQ you can get the number of occurences, like below:
int numOfOcuurences= s.Count( s=> s == tbFirstClub.Text);
lblResult1.Text = numOfOcuurences.ToString();
welcome to Stack Overflow.
I want to point out something you said.
else if(s.Contains(tbSecondClub.Text))
{
s.Count = lblResult2.Text; //problem is here
}
S is our string that we just read from the file.
You're saying assoung S.Count (The length of the string) to text.
I don't think this is what you want. We want to return the number of times specified strings show up in a specified file
Let's refactor this, (And add some tricks along the way).
// Let's create a dictionary to store all of our desired texts, and the counts.
var textAndCounts = new Dictionary<string, int>();
textAndCounts.Add(tbFirstClub.Text, 0); // Assuming the type of Text is string, change acccorrdingly
textAndCounts.Add(tbSecondClub.Text, 0);
//We added both out texts fields to our dictionary with a value of 0
// Read all the lines from the file.
var allLines = File.ReadAllLines(openFileName); /* using System.IO */
foreach(var line in allLines)
{
if(line.Contains(tbFirstClub.Text))
{
textAndCounts[tbFirstClub.Text] += 1; // Go to where we stored our count for our text and increment
}
if(line.Contains(tbSecondClub.Text))
{
textandCounts[tbSecondClub.Text] += 1;
}
}
This should solve your problem, but it's still pretty brittle. Optimally, we want to design a system that works for any number of strings and counts them.
So how would I do it?
public Dictionary<string, int> GetCountsPerStringInFile(IEnumerable<string> textsToSearch, string filePath)
{
//Lets use Linq to create a dictionary, assuming all strings are unique.
//This means, create a dictionary in this list, where the key is the values in the list, and the value is 0 <Text, 0>
var textsAndCount = textsToSearch.ToDictionary(text => text, count => 0);
var allLines = File.ReadAllLines(openFileName);
foreach (var line in allLines)
{
// You didn't specify if a line could maintain multiple values, so let's handle that here.
var keysContained = textsAndCounts.Keys.Where(c => line.Contains(c)); // take all the keys where the line has that key.
foreach (var key in keysContained)
{
textsAndCounts[key] += 1; // increment the count associated with that string.
}
}
return textsAndCounts;
}
The above code allows us to return a data structure with any amount of strings with a count.
I think this is a good example for you to save you some headaches going forward, and it's probably a good first toe-dip into design patterns. I'd suggest looking up some material on Data structures and their use cases.
I have been able to read the content of a web page and saved it into a file. This question is, how do I read for 10 different webpages without having to repeat the code over and over again. Is there a loop mechanism that can help? Here is what I have done:
static void Main(string[] args)
{
Task Task1 = new Task(() => ReadWriteWeb("http://www.hawaii.edu"));
Task1.Start();
Console.ReadLine();
}
static void ReadWriteWeb(string Url)
{
try
{
using (WebClient WebC = new WebClient())
{
string WebContents = WebC.DownloadString(Url);
Console.WriteLine(WebContents);
using (StreamWriter SW = new StreamWriter("myFile")
SW.WriteLine(WebContents + ". " + "The lenght of file is {0}", WebContents.Length);
}
}
catch (Exception e)
{
Console.WriteLine("The web content cannot be reached");
Console.WriteLine(e.Message);
}
}
Forgive me, but assuming you are aware of loops already as I hope you are here is an the answer I thought you would be looking for. This will download all the files simultaneously via a simple loop / multithreaded feature of linq.
public class Program
{
volatile static int fileNameCounter = 1;
static void Main(string[] args)
{
var listOfTasks = new List<Task>()
{
new Task(() => ReadWriteWeb("http://www.hawaii.edu")),
new Task(() => ReadWriteWeb("http://www.hawaii.edu")),
new Task(() => ReadWriteWeb("http://www.hawaii.edu")),
new Task(() => ReadWriteWeb("http://www.hawaii.edu"))
};
listOfTasks.AsParallel().ForAll(task => task.Start());
Console.ReadLine();
}
static async void ReadWriteWeb(string Url)
{
Console.WriteLine($"File {fileNameCounter} complete");
try
{
using (WebClient WebC = new WebClient())
{
string WebContents = await WebC.DownloadStringTaskAsync(Url);
Console.WriteLine(WebContents);
using (StreamWriter SW = new StreamWriter($"myFile{fileNameCounter++}"))
SW.WriteLine(WebContents + ". " + "The lenght of file is {0}", WebContents.Length);
}
}
catch (Exception e)
{
Console.WriteLine("The web content cannot be reached");
Console.WriteLine(e.Message);
}
}
}
Since I only had the one web url I listed the same one 4 times. You get the idea...
Standard looping constructs in C# include the for loop and the foreach loop.
In general, anything you could possibly want to know about C# can be found in the reference on MSDN.
Trying to check if the file is empty or not, and then write something like "the text is empty" into the document.
But whenever I do get the
the process cannot access the file because it is being used by another process
even though I'm closing the file after the write.
What am I missing here?
StreamWriter myWriter1 = new StreamWriter(resultpath);
List<string> a = File.ReadAllLines(path).ToList();
List<string> b = File.ReadAllLines(newPath).ToList();
foreach (string s in a)
{
Console.WriteLine(s);
if (!b.Contains(s))
{
myWriter1.WriteLine(s);
myWriter1.Close();
}
else
{
continue;
}
}
string[] resultfile = File.ReadAllLines(resultpath);
if (resultfile == null || resultfile.Length == 0)
{
myWriter1.WriteLine("Der er ikke nogen udmeldinger idag", true);
}
myWriter1.Close();
You can close & dispose file writer after writing to it in the loop and re-create it when you neet to write to the same file again.
Also note it is better to wrap it into using statement to ensure it wil be closed and set free unmanaged resources automatically (so you don't need to close it in the loop again and again).
List<string> a = File.ReadAllLines(path).ToList();
List<string> b = File.ReadAllLines(newPath).ToList();
using (var myWriter1 = new StreamWriter(resultpath, false))
{
foreach (string s in a)
{
Console.WriteLine(s);
if (!b.Contains(s))
myWriter1.WriteLine(s);
}
}
string[] resultfile = File.ReadAllLines(resultpath);
if (resultfile == null || resultfile.Length == 0)
{
using (var myWriter1 = new StreamWriter(resultpath, true))
{
myWriter1.WriteLine("Der er ikke nogen udmeldinger idag", true);
}
}
Try this code. You were closing the StreamWriter on each line that is in the 2 analized files,but if there is no coincidence, you never close it.
using (var myWriter1 = new StreamWriter(resultpath, true))
{
List<string> a = File.ReadAllLines(path).ToList();
List<string> b = File.ReadAllLines(newPath).ToList();
int coincidences=0;
foreach (string s in a)
{
Console.WriteLine(s);
if (!b.Contains(s))
{
myWriter1.WriteLine(s);
coincidences++;
}
}
if (coincidences == 0)
{
myWriter1.WriteLine("Der er ikke nogen udmeldinger idag", true);
}
}
Also,note that for IDisposable objects it's better to enclose it in a using clause,as it disposes all the resources when finished.
I cannot figure out how to read user-input in a loop (with Console.ReadLine). I'm trying to create a note that lets me store what ever the user inputs, and exits if he types exit.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Note myNote = new Note();
Note otherNote = new Note();
myNote.addText("Hi there");
Console.WriteLine(myNote.display());
otherNote.addText(Console.ReadLine());
Console.WriteLine(otherNote.display());
if (otherNote = "exit")
{
}
}
}
}
class Note
{
private string text = "";
private DateTime timeStamp = DateTime.Now;
private DateTime modifiedStamp = DateTime.Now;
int maxLength = 10;
public void addText(string sometext)
{
if (text.Length + sometext.Length < maxLength)
{
text += sometext;
modifiedStamp = DateTime.Now;
}
}
public string display()
{
return "Created: " + timeStamp.ToString() + "\n" +
"Modified: " + modifiedStamp.ToString() + "\n" +
"Content: " + text;
}
}
You need List of Notes in order to add as many notes as you want.
Additionally, you need to first save ReadLine input check if the user really asked to exit otherwise keep adding notes.
var myNotes = new List<Note>();
var firstNote = new Note();
firstNote.addText("Hi there");
Note note;
while (true)
{
var input = Console.ReadLine();
if (input.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
break;
}
note = new Note();
note.addText(input);
myNotes.Add(note);
}
The general format is to use something like this (a while loop with a break condition):
// put code above while loop that only needs to be executed once
while (true) {
// get the user input for every iteration, allowing to exit at will
String line = Console.ReadLine();
if (line.Equals("exit")) {
// exit the method.
return; // use "break" if you just want to exit the loop
}
// this is what will happen in the loop body since we didn't exit
// put whatever note stuff you want to execute again and again in here
}
You'll want to edit what goes into the body of this loop depending on what exactly you want done with your note instances. But generally, you repeatedly prompt a user for input until some condition is met and then you break out of the loop. You may decided that condition (e.g. "enter 10 notes"; "type exit"; etc.)
Per #n0rd's comment, here's how a do...while loop could work:
string input;
var myNotes = new List<Note>();
do{
input = Console.ReadLine();
if (!input.Equals("exit", StringComparison.OrdinalIgnoreCase)){
var note = new Note();
note.addText(input);
myNotes.Add(note);
}
} while (!input.Equals("exit", StringComparison.OrdinalIgnoreCase));
To loop Console.ReadLine() you can use this
`List<string> al = new List<string>(); //list to store string values
while(true)
{
string f = Console.ReadLine();
if(f == null) //check if string is null or not
{
break;
}
else
al.Add(f); //add strings to list
}`
One way to do it is this:
List<string> simpleList = new List<string> { "Alpha", "Bravo", "Charlie", "Delta", "Echo" }; //Dummy data source
Console.WriteLine("Enter a call sign to find in the list. Press X to exit: "); //Prompt
string callSign;
string exitKey = "x";
while ((callSign = Console.ReadLine().ToLower()) != exitKey)
{ //This is where the "Magic" happens
if (simpleList.Contains(callSign))
{
Console.WriteLine($"\"{callSign}\" exists in our simple list");//Output should the list contain our entry
Console.WriteLine(""); //Not really relevant, just needed to added spacing between input and output
}
else
{
Console.WriteLine($"\"{callSign}\" does not exist in our simple list"); //Output should the list not contain our entry
}
Console.WriteLine("");
Console.WriteLine("Enter a call sign to find in the list. Press X to exit: ");//Prompt
}
The line:
while ((callSign = Console.ReadLine().ToLower()) != exitKey) {
...
is where the loop happens. If the entry does not equal the exitKey, the steps are repeated.