I'm trying to teach myself how to edit files in C# and have encountered a problem. I am trying to allow the user to open a file that contains a sentence that says:
"How are you today, <name>?"
I have a class that will read the file and add the sentence to a List. Here is the code that I wrote for that:
class FileReader
{
public string reader(string sentence)
{
string f = sentence;
List<string> lines = new List<string>();
using (StreamReader r = new StreamReader(f))
{
string line;
while ((line = r.ReadLine()) != null)
{
lines.Add(line);
}
return lines.ToString();
}
}
}
Once this is returned as a string, I have another class that will read the list, and then will ask the user for a name. It will then replace <name> with the name the user input. Here is the code I've tried writing to handle this:
class Asker
{
public string asker(string sentence)
{
List<string> lines = new List<string>();
Console.Write("Enter Name: ");
string name = Console.ReadLine();
string text = File.ReadAllText(sentence);
text = text.Replace("<name>", name);
lines.Add(text);
File.WriteAllText(sentence, text);
return lines.ToString();
}
}
By the end of this class, the Asker class should return a list containing the new sentence where name now replaces <name> in the original sentence. In main, I get an error code every time I try to run it. Here is main:
static void Main(string[] args)
{
Console.Write("Enter the name of the story file: ");
string filename = Console.ReadLine();
FileReader read = new FileReader();
string uneditedSentence = read.reader(filename);
Asker ask = new Asker();
string newSentence = ask.asker(uneditedSentence);
Console.WriteLine(newSentence);
}
When I run this program I get a message that it stopped working and just crashes.
Few Edits are required in your code:
1) When you are returning lines.toString()>> it would return System.Collections.Generic.List`1[System.String] and not the text in the file. So you should lines and not lines.String().
so the return type of your function would be List.
Or if you want to return the string then code would be:
class FileReader
{
public string reader(string sentence)
{
string f = sentence;
string lines = "";
using (StreamReader r = new StreamReader(f))
{
string line;
while ((line = r.ReadLine()) != null)
{
lines +=line+ Environment.NewLine;
}
return lines;
}
}
}
2) In your asker class: asker function argument is the content of file and not the filename:
string text = File.ReadAllText(sentence)
so the above code will not work.
A better way: you dont need file reader class:
class Program
{
static void Main(string[] args)
{
Console.Write("Enter the name of the story file: ");
string filename = Console.ReadLine();
Asker ask = new Asker();
string newSentence = ask.asker(filename);
Console.WriteLine(newSentence);
string name = Console.ReadLine();
}
}
class Asker
{
public string asker(string sentence)
{
Console.Write("Enter Name: ");
string name = Console.ReadLine();
string text = File.ReadAllText(sentence);
text = text.Replace("<name>", name);
File.WriteAllText(sentence, text);
return text;
}
}
Your reader method accepts filename as the only argument and returns the contents of the file.
It means that in this line of code uneditedSentence is the contents of file filename:
string uneditedSentence = read.reader(filename);
Then, you pass this uneditedSentence to your asker:
string newSentence = ask.asker(uneditedSentence);
At the same time, your asker method has the following lines:
string text = File.ReadAllText(sentence);
File.WriteAllText(sentence, text);
which expects filepath while you provide contents of it.
It provides a error, because you provide an incorrect file path. The reason of this is very simple - naming. You name your variables inproperly and get confused.
Refer to MSDN documentation on ReadAllText and WriteAllText.
Also, it will not show proper results, because you apply ToString() to the List<string> expecting that it will be converted to the single string. However, it will simply result in something like System.Collections.Generic.List'1[System.String].
Here is how you should have done this:
class FileReader // Actually, it is a useless class, get rid of it
{
public string Read(string filename)
{
return File.ReadAllText(filename);
}
}
Related
I have a program that finds words within a text file and print them out. But this is a school assignment, and I need to use a certain degree of object oriented programming, like using different classes and interfaces.
So, the issue I have is that I have two public classes, that when called and adopted in the main class, with the main method, prints out the two string values I want.
The code looks like this
public class GetFilePath
{
public string FilePath;
public GetFilePath(string fn)
{
/// string path = "testfile.txt";
FilePath = fn;
}
public void SetFilename(string NewFilePath)
{
FilePath = NewFilePath;
}
}
public class GetSearchWord
{
public string WordSearch;
public GetSearchWord(string st)
{
WordSearch = st;
}
public void SetSearchTerm(string NewSearchTerm)
{
WordSearch = NewSearchTerm;
}
}
These are implemented into the main function as follows
Console.Write("please enter a file to search for: ");
// Call the constructor that has no parameters.
GetFilePath Filepath1 = new GetFilePath("");
Console.WriteLine(Filepath1.FilePath);
Filepath1.SetFilename("testfile.txt");
Console.WriteLine(Filepath1.FilePath);
// Call the constructor that has one parameter.
Console.Write("please enter a word to search for in the file: ");
GetSearchWord SearchedWord1 = new GetSearchWord("");
Console.WriteLine(SearchedWord1.WordSearch);
SearchedWord1.SetSearchTerm("true");
Console.WriteLine(SearchedWord1.WordSearch);
But I need to connect Filepath1.FilePath and SearchedWord1.WordSearch to the following strings
string FilePath = "";
string WordSearch = "";
As you can see those are null at the moment.
which are the key strings in my search function that actually searches up the lines with the words!
The FilePath and WordSearched strings are used as following
using (StreamReader fs = File.OpenText(FilePath))
{
int count = 0; //counts the number of times wordResponse is found.
int lineNumber = 0;
while (!fs.EndOfStream)
{
string line = fs.ReadLine();
lineNumber++;
int position = line.IndexOf(WordSearch);
if (position != -1)
{
count++;
Console.WriteLine("Match#{0} line {1}: {2}", count, lineNumber, line);
}
}
if (count == 0)
{
Console.WriteLine("your word was not found!");
}
else
{
Console.WriteLine("Your word was found " + count + " times!");
}
Console.WriteLine("Press enter to quit.");
Console.ReadKey();
}
what I have tried doing is setting
string WordSearch = SearchedWord1.WordSearch;
as an example of what I am trying to achive since, SearchedWord1.WordSearch is currently set to "true" which is the keyword I want to search my file for.
if I understood your question correctly then the following code should solve your problem(update your main code with the following):
Console.Write("please enter a file to search for: ");
// Call the constructor that has no parameters.
var filePathInput = Console.ReadLine();
GetFilePath Filepath1 = new GetFilePath(filePathInput);
Console.WriteLine(Filepath1.FilePath);
Filepath1.SetFilename("testfile.txt");
Console.WriteLine(Filepath1.FilePath);
// Call the constructor that has one parameter.
Console.Write("please enter a word to search for in the file: ");
var searchWordInput = Console.ReadLine();
GetSearchWord SearchedWord1 = new GetSearchWord(searchWordInput);
Console.WriteLine(SearchedWord1.WordSearch);
SearchedWord1.SetSearchTerm("true");
Console.WriteLine(SearchedWord1.WordSearch);
the change is that this code is getting the input from the user...
I am having trouble attempting to find words in a text file in C#.
I want to find the word that is input into the console then display the entire line that the word was found on in the console.
In my text file I have:
Stephen Haren,December,9,4055551235
Laura Clausing,January,23,4054447788
William Connor,December,13,123456789
Kara Marie,October,23,1593574862
Audrey Carrit,January,16,1684527548
Sebastian Baker,October,23,9184569876
So if I input "December" I want it to display "Stephen Haren,December,9,4055551235" and "William Connor,December,13,123456789" .
I thought about using substrings but I figured there had to be a simpler way.
My Code After Given Answer:
using System;
using System.IO;
class ReadFriendRecords
{
public static void Main()
{
//the path of the file
FileStream inFile = new FileStream(#"H:\C#\Chapter.14\FriendInfo.txt", FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(inFile);
string record;
string input;
Console.Write("Enter Friend's Birth Month >> ");
input = Console.ReadLine();
try
{
//the program reads the record and displays it on the screen
record = reader.ReadLine();
while (record != null)
{
if (record.Contains(input))
{
Console.WriteLine(record);
}
record = reader.ReadLine();
}
}
finally
{
//after the record is done being read, the progam closes
reader.Close();
inFile.Close();
}
Console.ReadLine();
}
}
Iterate through all the lines (StreamReader, File.ReadAllLines, etc.) and check if
line.Contains("December") (replace "December" with the user input).
Edit:
I would go with the StreamReader in case you have large files. And use the IndexOf-Example from #Matias Cicero instead of contains for case insensitive.
Console.Write("Keyword: ");
var keyword = Console.ReadLine() ?? "";
using (var sr = new StreamReader("")) {
while (!sr.EndOfStream) {
var line = sr.ReadLine();
if (String.IsNullOrEmpty(line)) continue;
if (line.IndexOf(keyword, StringComparison.CurrentCultureIgnoreCase) >= 0) {
Console.WriteLine(line);
}
}
}
As mantioned by #Rinecamo, try this code:
string toSearch = Console.ReadLine().Trim();
In this codeline, you'll be able to read user input and store it in a line, then iterate for each line:
foreach (string line in System.IO.File.ReadAllLines(FILEPATH))
{
if(line.Contains(toSearch))
Console.WriteLine(line);
}
Replace FILEPATH with the absolute or relative path, e.g. ".\file2Read.txt".
How about something like this:
//We read all the lines from the file
IEnumerable<string> lines = File.ReadAllLines("your_file.txt");
//We read the input from the user
Console.Write("Enter the word to search: ");
string input = Console.ReadLine().Trim();
//We identify the matches. If the input is empty, then we return no matches at all
IEnumerable<string> matches = !String.IsNullOrEmpty(input)
? lines.Where(line => line.IndexOf(input, StringComparison.OrdinalIgnoreCase) >= 0)
: Enumerable.Empty<string>();
//If there are matches, we output them. If there are not, we show an informative message
Console.WriteLine(matches.Any()
? String.Format("Matches:\n> {0}", String.Join("\n> ", matches))
: "There were no matches");
This approach is simple and easy to read, it uses LINQ and String.IndexOf instead of String.Contains so we can do a case insensitive search.
For finding text in a file you can use this algorithim use this code in
static void Main(string[] args)
{
}
try this one
StreamReader oReader;
if (File.Exists(#"C:\TextFile.txt"))
{
Console.WriteLine("Enter a word to search");
string cSearforSomething = Console.ReadLine().Trim();
oReader = new StreamReader(#"C:\TextFile.txt");
string cColl = oReader.ReadToEnd();
string cCriteria = #"\b"+cSearforSomething+#"\b";
System.Text.RegularExpressions.Regex oRegex = new
System.Text.RegularExpressions.Regex(cCriteria,RegexOptions.IgnoreCase);
int count = oRegex.Matches(cColl).Count;
Console.WriteLine(count.ToString());
}
Console.ReadLine();
using System;
using System.IO;
namespace GetFilesFromDirectory
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Write your Name of Disc");
string myDisc = Console.ReadLine();
string myDisc1 = "#\"";
Console.WriteLine("Write your Directory");
string myDir1 = Console.ReadLine();
string myDir = ":\\";
string myDir2 = "\\\"";
string myPath = myDisc1 + myDisc + myDir + myDir1 + myDir2;
Console.WriteLine(myPath);
string[] filePaths = Directory.GetFiles(myPath);
foreach (var files in filePaths)
{
Console.WriteLine(files);
}
Console.ReadLine();
}
}
}
Try this
static void Main(string[] args)
{
Console.WriteLine("Write your Name of Disc");
//You need to add :\ to make it a fullPath
string myDisc = Console.ReadLine()+":\\";
Console.WriteLine("Write your Directory");
string myDir1 = Console.ReadLine();
string myPath = Path.Combine(myDisc , myDir1);
Console.WriteLine(myPath);
string[] filePaths = Directory.GetFiles(myPath);
foreach (var files in filePaths)
{
Console.WriteLine(files);
}
Console.ReadLine();
}
What are you doing is creating a string wich is the literal reprentation of the string you want but you don't need to do this.For example if you write this:
string path=#"c:\dir\subdir"; its real value will be c:\dir\subdir
instead this "#\"c:\\dir\\subdir\""; will be
#"c:\dir\subdir"
Read these articles to better understand string literals and verbatim strings https://msdn.microsoft.com/en-us/library/aa691090(v=vs.71).aspx https://msdn.microsoft.com/en-us/library/362314fe.aspx
https://msdn.microsoft.com/en-us/library/h21280bw.aspx
From what I can tell your myPath will look like #"discName:\dirName\", you don't need to append the #" or ".
These symbols are used when you are creating a new string variable to note that is a String literal, but you are including these characters in the actual string you are generating.
In other words, remove myDisc1 and myDir2
Better than that, as noted by DrKoch
string myPath = Path.Combine(myDisc + #":\", myDir1);
I have text file which i need to update according to the regex match but as soon as my program tries to write a line into text file it is giving following error..
The process cannot access the file 'D:\Archieve\20140123.text' because it is being used by another process.
Here is my C# code..
static void Main(string[] args)
{
string textfilename="";
string strDateTime = DateTime.Now.ToString("yyyyMMdd");
string strformatedatetime = DateTime.Now.ToString("yyyy/MM/dd");
if (strDateTime != "") {
string loc = "D:\\Archieve\\";
string date=strDateTime;
string text=".text";
textfilename = loc + date + text;
File.Create(textfilename);
}
string pattern = "^" + strformatedatetime + ".*";
string FileToCopy = "D:\\ipdata.txt";
string NewCopy =textfilename;
StringBuilder sb = new StringBuilder("");
List<string> newLines = new List<string>();
if (System.IO.File.Exists(FileToCopy) == true)
{
string[] lines = File.ReadAllLines(FileToCopy);
foreach (string line in lines)
{
if (Regex.IsMatch(line, pattern))
{
sb.Append(line + System.Environment.NewLine);
TextWriter tsw = new StreamWriter(textfilename,true);
//Writing text to the file.
tsw.WriteLine(sb);
//Close the file.
tsw.Close();
}
}
}
}
I am getting above defined error at this line of code...
TextWriter tsw = new StreamWriter(textfilename,true);
Where am i going wrong ?
You don't need to have a separate instruction to create a file.
The StreamWriter will take care of it: Here is the description of the constructor you user
> Initializes a new instance of the StreamWriter class for the specified
> file by using the default encoding and buffer size. If the file
> exists, it can be either overwritten or appended to. If the file does
> not exist, this constructor creates a new file.
Use File.Create(textfilename).Close();
As the error message suggests
I know how to go to a specific line but I don't know how to update that specific line in the string. I have tried the Replace functionality but it overwrites the duplicates as well. Any ideas?
static string GetLine(string text, int lineNo)
{
string[] lines = text.Replace("\r", "").Split('\n');
return lines.Length >= lineNo ? lines[lineNo - 1] : null;
}
static void Main(string[] args)
{
string file = "D:\\random.text";
string contents = "";
string text="random";
contents = File.ReadAllText(file);
finale=GetLine(contents,lines);
// Console.ReadLine();
if(finale.Contains(text))
{
finale.Replace(text,"Random");
System.Console.WriteLine(finale);
Console.ReadLine();
}
}
Strings are immutable type which means you cant alter an existing string. string.Replace returns the replaced string and you need to assign it back.
if(finale.Contains(text))
{
finale = finale.Replace(text,"Random"); //<- note here
System.Console.WriteLine(finale);
Console.ReadLine();
}
From there you need to rebuild the string from the string array as noted by Philippe. A complete example (but untested):
static string[] GetLines(string text)
{
return text.Replace("\r", "").Split('\n');
}
static string GetLine(string[] lines, int lineNo)
{
return lines.Length >= lineNo ? lines[lineNo - 1] : null;
}
static void Main(string[] args)
{
string file = "D:\\random.text";
string contents = "";
string text="random";
contents = File.ReadAllText(file);
var lines = GetLines(contents);
finale = GetLine(lines, lineNo);
//Console.ReadLine();
if (finale == null)
return;
if(finale.Contains(text))
{
finale = finale.Replace(text, "Random");
System.Console.WriteLine(finale);
Console.ReadLine();
}
lines[lineNo] = finale;
contents = string.Join('\n', lines);
}
And best of all, you don't need all that split function at all. .NET has that functionality and it does lazily (on demand) which is a bonus.
See for File.ReadLines if you're using .NET 4.0 and above.
The quickest solution would be to keep the array returned by Split and then use String.Join to rebuild what you started with.
Just rebuild the string with string builder as you read the file.
static void Main(string[] args)
{
string file = "D:\\random.txt";
string find = "random";
string replace = "Random";
StringBuilder resultList = new StringBuilder();
using (var stream = File.OpenText(file))
{
while (stream.Peek() >= 0)
{
string line = stream.ReadLine();
if(line == find)
{
line = replace;
}
resultList.AppendLine(line);
}
}
string result = resultList.ToString();
Console.WriteLine(result);
Console.Read();
}