Reading specific lines with unknown placement in C# - c#

I am trying to code a program to read out user-groups from a .txt-file and to put said groups into a listbox. An example for a group list would be the following:
User
-------------
Group1
Group2
Group3
[space]
[space]
next user
Every user has is in an unknown amount of groups, thats why there are two spaces, just to seperate everything.
Here is my progress so far:
private void Button_Click(object sender, RoutedEventArgs e) {
//users.txt contains all users
//in the same directory there are multiple lists with given groups
StreamReader sr = new StreamReader("c:\\ADHistory\\users.txt", System.Text.Encoding.Default);
string line = string.Empty;
try {
//Read the first line of text
line = sr.ReadLine();
//Continue to read until you reach end of file
while (line != null) {
listboxNames.Items.Add(line);
//Read the next line
line = sr.ReadLine();
}
//close the file
sr.Close();
}
catch (Exception f)
{
MessageBox.Show(f.Message.ToString());
}
finally
{
//close the file
sr.Close();
}
}
private void listboxNames_SelectionChanged(object sender, SelectionChangedEventArgs e) {
//as soon as you choose a user from the first list
//you may choose a date to look at all groups the user is in.
listboxDates.Items.Clear();
DirectoryInfo dinfo = new DirectoryInfo(#"C:\ADHistory");
FileInfo[] Files = dinfo.GetFiles("*.txt");
//this adds all dates into the second listbox
//and removes users.txt from the list.
foreach (FileInfo file in Files) {
listboxDates.Items.Add(file.Name);
}
for (int n = listboxDates.Items.Count - 1; n >= 0; --n)
{
string removelistitem = "users";
if (listboxDates.Items[n].ToString().Contains(removelistitem))
{
listboxDates.Items.RemoveAt(n);
}
//this displays the user below the listboxes,
//because of styling purposes
string user = Convert.ToString(this.listboxNames.SelectedItem);
labelName.Content = user;
}
}
//here we have my main problem.
//I can't find a solution to add the groups to the last listbox
private void listboxDates_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string user = Convert.ToString(labelName.Content);
listboxGroups.Items.Clear();
string path = "C:\\ADHistory\\";
path += Convert.ToString(this.listboxDates.SelectedItem);
foreach (string line in File.ReadLines(path))
{
if (line.Contains(user))
{
while (line != " ")
{
listboxGroups.Items.Add(line);
}
}
}
}
I really hope you can help me.
EDIT
This question has been answered, so there is no need for mor answers.
Thanks for all the comments :)

Your problem is, when the line for the user is found, you test if line == " " without proceeding to the next and your while loop should exit immediately then
Use for loop instead of for each. Have your while loop when you find the line for user as the same, and increase the loop variable with ++ inside the while loop and read the next line. Don't forget to check for the string array length before setting line = fileLines[lineIndex]
Therefore, here is the code that should work for you
string[] fileLines = File.ReadAllLines(path);
for (int lineIndex = 0; lineIndex < fileLines.Length; lineIndex++)
{
string line = fileLines[lineIndex];
if (line.Contains(user))
{
while(++lineIndex < fileLines.Length && (line = fileLines[lineIndex]) != " ")
{
listboxGroups.Items.Add(line);
}
break;
}
}
However, if the file is huge, you might want not to read all it's lines into memory, here is another approach which works with File.ReadLines()
IEnumerator<string> fileLines = File.ReadLines(path).GetEnumerator();
while (fileLines.MoveNext())
{
string line = fileLines.Current;
if (line.Contains(user))
{
while (fileLines.MoveNext())
{
line = fileLines.Current;
if (line == " ")
{
break;
}
listboxGroups.Items.Add(line);
}
break;
}
}

Related

Can you help me on textchanged ans copy

Hello I would like to be able to change the text of my txtFiles textbox at each iteration of files when there are several files.
And also be able to copy only one file at a time when I want it even if there are several files in the directory.
I declared the textchanged event.
I have declared the txtFiles_TextChanged function but I don't know what to put in it to make the text of the txtFiles textbox change with each iteration of files.
I declared txtFiles.Text = ConvertToString (files [i]);
to change the text in the textbox.
I would also like to be able to copy only one file at a time but it wipes out all the txt files.
How do you resolve this?
string sourceDir =
#"C:\Users\PORTABLEHP\Documents";
string destDir =
#"C:\Users\PORTABLEHP\Documents\
xgen";
public évent EventHandler
textchanged;
private void btnCopy(object
sender,EventArgs e)
{
try
{
string [] txtList = Directory.
GetFiles(sourceDir,"*.txt");
foreach(string f in txtList)
{
try
{
string fName = f.Substring
(sourceDir.Length + 1);
string [] files = new string
[sourceDir.Length];
progressBar1.Value = 1;
progressBar1.Minimum = 0;
progressBar1.Maximum =
files.Length;
for(int i = 1;i < files.Length;
i++)
{
progressBar1.PerformStep();
//To have the text change from the
textbox
txtFiles.Text = ConvertToString
(files[i]);
File.Copy(Path.Combine
(sourceDir,fName), Path.Combine
(destDir,fName), true);
}
}
catch(IOException copyerror)
{
MessageBox.Show(copyerror.Message);
}
}
}
catch (DirectoryNotFoundException
dirnotfound)
{
MessageBox.Show
(dirnotfound.Message);
private void txtFiles_TextChanged
(object sender,EventArgs e)
{
// I don't know ?
}
So if I got you right, you need to do a little change in your code
Change
txtFiles.Text = ConvertToString(files[i]);
To
txtFiles.Text = $"{ Path.GetFileName(f)} was copied"; //f was declared as string in your first loop that contains the file path

Append string in a specific place of a text file

I have hundreds of files in a directory. Many of the text files have the Code Column values as blank and i need to iterate over all the text files and fill it. I am able to write the code to add the code value in a new line, but i am not able to write it under code column. String value is: "STRINGTOENTER". I only want it be entered in the 1st line after the header. The last line should be left alone
Id Code File_Number Suffix Check_Number Check_Date
047 7699 01 99999 11/11/2012
1 -6.15
Below is my code snippets that add the value at a newline. I think I need to do a regular expression or a tab delimited type solution here.
public static void AddAStringtoAllTextFiles()
{
try
{
string path = #"C:\Users\ur\Desktop\TestFiles\";
string[] fileEntries = Directory.GetFiles(path);
for (int i = 0; i < fileEntries.Length; i++)
{
File.AppendAllText(fileEntries[i], "STRINGTOENTER" + Environment.NewLine);
}
}
catch (Exception e)
{
throw e;
}
}
EDITED
please try this with the assumption that its space(s) delimited.
its working on my VS2017 and kindly add the using statement on the top as below .
using System.Text.RegularExpressions
public static void AddAStringtoAllTextFiles()
{
try
{
string path = #"C:\Users\ur\Desktop\TestFiles\";
var fileEntries = Directory.GetFiles(path);
int indexPosition2InsertData=1;
foreach (var entry in fileEntries)
{
var lines = File.ReadAllLines(entry);
for (var index = 1; index < lines.Length; index++) //starting from first row, leaving the header
{
var split= Regex.Split(lines[index].Trim(), #"\s{1,}"); //reading the line with space(s)
if(split.Length==5) //edited //checking if the row is not blank
{
var list = split.ToList(); //convert to list to insert
list.Insert(indexPosition2InsertData, "STRINGTOENTER"); //inserting at the index 1
lines[index] = string.Join("\t", list);
}
}
File.WriteAllLines(entry, lines);
}
}
catch (Exception e)
{
throw e;
}
}
I am getting this after running the code.
Id Code File_Number Suffix Check_Number Check_Date
047 STRINGTOENTER 7699 01 99999 11/11/2012
1 -6.15
Please let me know if this helps.
Assuming each file has the right tab delimitation (and that's a big assumption given the question quality)
// Get the files
var fileEntries = Directory.GetFiles(path);
// iterate through each file name
foreach (var entry in fileEntries)
{
// Load the File into the lines array
var lines = File.ReadAllLines(entry);
// Iterate over each line
if(lines.Length >1)
{
// Split the lines by tab
var split = lines[1].Split('\t');
// your code should be at array index 1
split[1] = "STRINGTOENTER";
// write the whole line back
lines[1] = string.Join("\t", split);
// write the file
File.WriteAllLines(entry, lines);
}
}
Note : you should probably do this with a CSV parser, this was only for academic purposes and totally untested
I want to show my desired solution based on your input. Amazing how a simple piece of code can contribute to solving a larger and a complex problem. Thanks again!
public static void AddClientCodetoAllTextFiles(string update_batch_with_clientcode, string batchfilepathtobeupdated)
{
try
{
var fileEntries = Directory.GetFiles(#batchfilepathtobeupdated.Trim());
foreach (var entry in fileEntries)
{
var lines = File.ReadAllLines(entry);
if (lines.Length > 1)
{
for (int i = 1; i < lines.Length - 1; i++)
{
var split = lines[i].Split('\t');
split[1] = update_batch_with_clientcode.Trim();
lines[i] = string.Join("\t", split);
File.WriteAllLines(entry, lines);
}
}
}
}
catch (Exception e)
{
throw e;
}
}

How read and search multiple txt files in listBox with (in) one button c#?

private void btnOpen_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == DialogResult.OK)
{
listBox1.Items.Clear();
string[] allfiles = Directory.GetFiles(fbd.SelectedPath, "*.txt*",
SearchOption.AllDirectories);
foreach (string file in allfiles)
{
FileInfo info = new FileInfo(file);
listBox1.Items.Add(Path.GetFileName(file));
}
}
}
There is listbox1 with all .txt files from direcory and subfolder...
Now I need from this listBox all files and search by some string.
Can I iterate loop and read file by file?
I don't have an idea how read and search files, need I open first, then store a data of file somewhere, maybe list or listView?
First, I would use a class of its own to store your search results. When we search files, and if we find the keyword we're searching for, we'd create an object of this class and at it to a list. Something like this:
public class SearchResults
{
public string FilePath { get; set; }
public string SearchWord { get; set; }
public int Occurences { get; set; }
}
Then you can use the System.IO.File class to read your files. Remember this is not the only way, but merely one way of doing it. Here I have a list of file names, which is equivalent to the array you have in your program.
var searchTerm = "Hello";
var fileList = new List<string>() { "A.txt", "B.txt", "C.txt" };
var resultList = new List<SearchResults>();
// Iterate through files. You already are doing this.
foreach (var file in fileList)
{
// Check to see if file exists. This is a second line of defense in error checking, not really necessary but good to have.
if (File.Exists(file))
{
// Read all lines in the file into an array of strings.
var lines = File.ReadAllLines(file);
// In this file, extract the lines contain the keyword
var foundLines = lines.Where(x => x.Contains(searchTerm));
if (foundLines.Count() > 0)
{
var count = 0;
// Iterate each line that contains the keyword at least once to see how many times the word appear in each line
foreach (var line in foundLines)
{
// The CountSubstring helper method counts the number of occurrences of a string in a string.
var occurences = CountSubstring(line, searchTerm);
count += occurences;
}
// Add the result to the result list.
resultList.Add(new SearchResults() { FilePath = file, Occurences = count, SearchWord = searchTerm });
}
}
}
The CountSubstring() helper method.
public static int CountSubstring(string text, string value)
{
int count = 0, minIndex = text.IndexOf(value, 0);
while (minIndex != -1)
{
minIndex = text.IndexOf(value, minIndex + value.Length);
count++;
}
return count;
}

how I can copy the text in a specified field, without mention the line number

I have the next code :
private void button1_Click_1(object sender, EventArgs e)
{
string path = AppDomain.CurrentDomain.BaseDirectory.ToString();
var link = File.ReadLines(path + "test.txt").ToArray();
var lines = File.ReadAllLines(path + "test2.txt");
foreach (var txt in link )
{
if (txt.Contains("Output="))
{
var outputPath = txt.Split('=')[1];
if (File.Exists(path + "test2.txt"))
{
var modifiedLines = lines.Select(line =>
{
if (line.StartsWith("outlog=\""))
{
return string.Format("outlog=\"{0}\"", outputPath);
}
else
{
return line;
}
});
File.WriteAllLines(path+ "test2.txt", modifiedLines);
}
}
}
With this code I whan to copy what is after equel from Output="C:\temp\out.log"(who is in test.txt), after equal in outlog=(who is in test2.txt).
How I can copy the text who exists in one text file test.txt, in a specified location from a second field test2.txt, without mentioned the line number ?
Here I put just a row, but in my files text I have many rows, but I think I make this to work, I handle with another rows.
test.txt have
Licfile="C:\temp\lic.lic"
Output="C:\temp\out.log"
Title="name"
test2.txt have
outlog=
license=
lmgr_files=
license_path=
and after runing the code the test2.txt I want to looks like this:
outlog="C:\temp\out.log"
license_path="C:\temp\lic.lic"
lmgr_files=false
license=true
I am confused about your problem but i just want to try to give you an opinion. I hope it may be help you. But line numbers are really important for these problem.
String[] arrayOld = File.ReadAllLines(#"C:\test.txt");
String[] arrayNew = new string[arrayOld.Length];
if (arrayOld[0].Contains("Licfile=")) // If statements could be more
{
Array.Copy(arrayOld,0,arrayNew,0,2); // How many line will add
}
for (int i = 0; i < 2; i++)
{
File.AppendAllText(#"D:\test2.txt", arrayNew[i] + Environment.NewLine); // It'll add all lines
}
P.S.: Don't forget to add strings like lineOne = "outlog=" + locString; etc.

search text file using c# and display the line number and the complete line that contains the search keyword

I require help to search a text file (log file) using c# and display the line number and the complete line that contains the search keyword.
This is a slight modification from: http://msdn.microsoft.com/en-us/library/aa287535%28VS.71%29.aspx
int counter = 0;
string line;
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
while((line = file.ReadLine()) != null)
{
if ( line.Contains("word") )
{
Console.WriteLine (counter.ToString() + ": " + line);
}
counter++;
}
file.Close();
Bit late to the game on this one, but happened across this post and thought I'd add an alternative answer.
foreach (var match in File.ReadLines(#"c:\LogFile.txt")
.Select((text, index) => new { text, lineNumber = index+ 1 })
.Where(x => x.text.Contains("SEARCHWORD")))
{
Console.WriteLine("{0}: {1}", match.lineNumber, match.text);
}
This uses:
File.ReadLines, which eliminates the need for a StreamReader, and it also plays nicely with LINQ's Where clause to return a filtered set of lines from a file.
The overload of Enumerable.Select that returns each element's index, which you can then add 1 to, to get the line number for the matching line.
Sample Input:
just a sample line
another sample line
first matching SEARCHWORD line
not a match
...here's aSEARCHWORDmatch
SEARCHWORD123
asdfasdfasdf
Output:
3: first matching SEARCHWORD line
5: ...here's aSEARCHWORDmatch
6: SEARCHWORD123
To export do Excel you can use the CSV file format, like the Pessimist wrote. If you are uncertain about what to write, try entering some data in MS Excel and click on "Save As" option in the Menu and choose CSV as file type.
Take care when writing a CSV file format as in some languages the default for separating values is not the comma. In brazilian portuguese, for example, the default is comma as decimal separator, dot as thousands separator and semicolon for separating values. Mind the culture when writing that.
The other alternative is using horizontal tabs as separators. Experiment to write a string, press the TAB key and then another string and paste it into Microsoft Excel. It is the default separator in that program.
If you're using an ad-hoc solution to your specific problem, either alternatives can be used without much thinking. If you are programming something to be used by other persons (or in other environments), mind the culture specific differences.
Oh, I've just remembered now: you can write a Spreadsheet using XML, you can do that with only the .NET package. I've done that years ago with C# .NET 2.0
I had a requirement where I needed to search through a list of directories looking for particular file types, containing a specific search terms but excluding other terms.
For example let's say you wanted to look through C:\DEV and only find .cs files that have terms "WriteLine" and "Readline" but not the term "hello".
I decided to write a small c# utility to do just this:
This is how you call it:
class Program
{
//Syntax:
//FileSearch <Directory> EXT <ext1> <ext2> LIKE <TERM1> <TERM2> NOT <TERM3> <TERM4>
//Example:
//Search for all files recursively in C:\Dev with an extension of cs that contain either "WriteLine" or "Readline" but not "hello"
//FileSearch C:\DEV EXT .cs LIKE "WriteLine" "ReadLine" NOT "hello"
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("FileSearch <Directory> EXT <EXT1> LIKE <TERM1> <TERM2> NOT <TERM3> <TERM4>");
return;
}
Search s = new Search(args);
s.DoSearch();
}
}
This is the implementation:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
class Hit
{
public string File { get; set; }
public int LineNo { get; set; }
public int Pos { get; set; }
public string Line { get; set; }
public string SearchTerm { get; set; }
public void Print()
{
Console.WriteLine(File);
Console.Write("(" + LineNo + "," + Pos + ") ");
Console.WriteLine(Line);
}
}
class Search
{
string rootDir;
List<string> likeTerms;
List<string> notTerms;
List<string> extensions;
List<Hit> hitList = new List<Hit>();
//FileSearch <Directory> EXT .CS LIKE "TERM1" "TERM2" NOT "TERM3" "TERM4"
public Search(string[] args)
{
this.rootDir = args[0];
this.extensions = ParseTerms("EXT", "LIKE", args);
this.likeTerms = ParseTerms("LIKE", "NOT", args);
this.notTerms = ParseTerms("NOT", "", args);
Print();
}
public void Print()
{
Console.WriteLine("Search Dir:" + rootDir);
Console.WriteLine("Extensions:");
foreach (string s in extensions)
Console.WriteLine(s);
Console.WriteLine("Like Terms:");
foreach (string s in likeTerms)
Console.WriteLine(s);
Console.WriteLine("Not Terms:");
foreach (string s in notTerms)
Console.WriteLine(s);
}
private List<string> ParseTerms(string keyword, string stopword, string[] args)
{
List<string> list = new List<string>();
bool collect = false;
foreach (string arg in args)
{
string argu = arg.ToUpper();
if (argu == stopword)
break;
if (argu == keyword)
{
collect = true;
continue;
}
if(collect)
list.Add(arg);
}
return list;
}
private void SearchDir(string dir)
{
foreach (string file in Directory.GetFiles(dir, "*.*"))
{
string extension = Path.GetExtension(file);
if (extension != null && extensions.Contains(extension))
SearchFile(file);
}
foreach (string subdir in Directory.GetDirectories(dir))
SearchDir(subdir);
}
private void SearchFile(string file)
{
using (StreamReader sr = new StreamReader(file))
{
int lineNo = 0;
while (!sr.EndOfStream)
{
int pos = 0;
string term = "";
string line = sr.ReadLine();
lineNo++;
//Look through each likeTerm
foreach(string likeTerm in likeTerms)
{
pos = line.IndexOf(likeTerm, StringComparison.OrdinalIgnoreCase);
if (pos >= 0)
{
term = likeTerm;
break;
}
}
//If found make sure not in the not term
if (pos >= 0)
{
bool notTermFound = false;
//Look through each not Term
foreach (string notTerm in notTerms)
{
if (line.IndexOf(notTerm, StringComparison.OrdinalIgnoreCase) >= 0)
{
notTermFound = true;
break;
}
}
//If not term not found finally add to hitList
if (!notTermFound)
{
Hit hit = new Hit();
hit.File = file;
hit.LineNo = lineNo;
hit.Pos = pos;
hit.Line = line;
hit.SearchTerm = term;
hitList.Add(hit);
}
}
}
}
}
public void DoSearch()
{
SearchDir(rootDir);
foreach (Hit hit in hitList)
{
hit.Print();
}
}
}

Categories