Not detecting empty/null lines - c#

So I am trying to use a config file that will have commonly used data each time you open the program, in this example a name which will be on the first line.
The issue is that I want to make sure that each individual line that would store something (name = line1, dob = line2) cant be empty. But it doesnt seem to notice that the config is empty.
Console.WriteLine("Finding config");
var folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\imsammstbot";
var filePath = folderPath + "\\tbot.config";
if (File.Exists(filePath))
{
Console.WriteLine("Config loading");
Console.WriteLine(filePath);
string[] cfgdata = File.ReadAllLines(filePath);
Console.WriteLine(cfgdata);
int linenum = 0;
foreach (string line in cfgdata)
{
if (String.IsNullOrEmpty(line) || String.IsNullOrWhiteSpace(line))
{
Console.WriteLine("Config empty\nGenerating new config file");
newcfg();
}
if (++linenum == 1) { string name = line; }
}
}
else
{
Console.WriteLine("No config found\nGenerating new config file");
newcfg();
}

Your foreach only runs if there is at least 1 line. To create a new config when there are 0 lines, you need to do an explicit check + corresponding action for that:
string[] cfgdata = File.ReadAllLines(filePath);
if (cfgdata.Length == 0) newcfg();
You probably also need to provide further handling after that, e.g. if you want the newly created config to be used, then you'd need to also read the newly created file:
string[] cfgdata = File.ReadAllLines(filePath);
if (cfgdata.Length == 0)
{
newcfg();
cfgdata = File.ReadAllLines(filePath);
if (cfgdata.Length == 0)
{
throw new Exception("Config file is empty, despite just creating a new one.")
}
}
foreach (string line in cfgdata)
{
// ...
}

Related

Why am i receiving a "The process cannot access the file because it is being used by another process."

Im trying to process a set of files, i have a given number of txt files, which im currently joining into 1 txt file to apply filters to. The creation of the 1 file from multiple works great. But i have 2 questions and 1 error i cant seem to get around.
1 - Im getting an error when i try to read the newly created file so i can apply the filters. "The process cannot access the file because it is being used by another process."
2 - Am i approaching this the correct or more efficient way? by that i mean can the reading and filtering be applied before creating the concatenated file? I mean i still need to create a new file, but it would be nice to be able to apply everything before creating so that the file is already cleaned and ready for use outside the application.
Here is the current code that is having the issue and the 1 commented line that was my other attempt at releasing the file
private DataTable processFileData(string fname, string locs2 = "0", string effDate = "0", string items = "0")
{
DataTable dt = new DataTable();
string fullPath = fname;
try
{
using (StreamReader sr = new StreamReader(File.OpenRead(fullPath)))
//using (StreamReader sr = new StreamReader(File.Open(fullPath,FileMode.Open,FileAccess.Read, FileShare.Read)))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
if (!String.IsNullOrWhiteSpace(line))
{
string[] headers = line.ToUpper().Split('|');
while (dt.Columns.Count < headers.Length)
{
dt.Columns.Add();
}
string[] rows = line.ToUpper().Split('|');
DataRow dr = dt.NewRow();
for (int i = 0; i < rows.Count(); i++)
{
dr[i] = rows[i];
}
dt.Rows.Add(dr);
}
}
//sr.Close();
sr.Dispose();
}
string cls = String.Format("Column6 NOT LIKE ('{0}')", String.Join("','", returnClass()));
dt.DefaultView.RowFilter = cls;
return dt;
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
return dt;
}
Here is the concatenation method:
private void Consolidate(string fileType)
{
string sourceFolder = #"H:\Merchant\Strategy\Signs\BACKUP TAG DATA\Wave 6\" + sfld;
string destinationFile = #"H:\Merchant\Strategy\Signs\BACKUP TAG DATA\Wave 6\" + sfld + #"\"+ sfld + #"_consolidation.txt";
// Specify wildcard search to match TXT files that will be combined
string[] filePaths = Directory.GetFiles(sourceFolder, fileType);
StreamWriter fileDest = new StreamWriter(destinationFile, true);
int i;
for (i = 0; i < filePaths.Length; i++)
{
string file = filePaths[i];
string[] lines = File.ReadAllLines(file);
if (i > 0)
{
lines = lines.Skip(1).ToArray(); // Skip header row for all but first file
}
foreach (string line in lines)
{
fileDest.WriteLine(line);
}
}
if (sfld == "CLR")
{
clrFilter(destinationFile);
}
if (sfld == "UPL")
{
uplFilter(destinationFile);
}
if (sfld == "HD")
{
hdFilter(destinationFile);
}
if (sfld == "PD")
{
pdFilter(destinationFile);
}
fileDest.Close();
fileDest.Dispose();
}
What im trying to accomplish is reading min(2 or 3 txt files and as much as 13 txt files) and applying some filtering. But im getting this error:
"The process cannot access the file because it is being used by another process."
You're disposing the stream reader with the following line
sr.Dispose();
Using a 'Using' statement will dispose after the stream goes out of context. So remove the Dispose line (if it wasn't clear below)

How to count lines

how do i count the line in log file and create a new log files of it?
Below is my log file :
DDD.CGLOG
ID|AFP|DATE|FOLDER
1|DDD|20181204|B
2|DDD|20181104|B
3|DDD|20181004|B
FFF.CGLOG
ID|AFP|DATE|FOLDER
1|FFF|20181204|B
2|FFF|20181104|B
WWW.CGLOG
ID|AFP|DATE|FOLDER
1|WWW|20181204|B
i want to count the line and create a new log file as below :
DDD_QTY.Log
AFP|QTY
DDD|3
EEE_QTY.Log
AFP|QTY
EEE|2
WWW_QTY.Log
AFP|QTY
WWW|1
Below is what i have tried. I have managed to get the count from each log file inside the folder, now i just need to write the count into a new log file using a same name with existing log file.
string[] ori_Files = Directory.GetFiles(#"F:\Work\FLP Code\test", "*.CGLOG*", SearchOption.TopDirectoryOnly);
foreach (var file in ori_Files)
{
using (StreamReader file1 = new StreamReader(file))
{
string line;
int count = 0;
while ((line = file1.ReadLine()) != null)
{
Console.WriteLine(line);
count++;
}
Console.WriteLine(count);
}
}
Console.ReadLine();
Since you only want to count lines, You can keep it simple. Assuming your file name dictates the AFP value
static long CountLinesInFile(string fileName,string outputfile)
{
var afp = Path.GetFileNameWithoutExtension(fileName);
var lineCount = File.ReadAllLines(fileName).Length;
File.WriteAllText(outputfile,$"AFP|QTY{Environment.NewLine}{afp}|{lineCount -1}");
return lineCount-1;
}
Please note you are counting a line less(headers are not counted as in your example). In case the file is different from AFP term, you can use regex to parse the AFP Term from the any line other than the header line in each term. Example Regex for parsing AFP Term
new Regex(#"^[0-9]+\|(?<AFP>[a-zA-Z]+)\|[0-9]+\|[a-zA-Z]+$")
Update
In case your file is pretty large (say 15-20Gb - considering it is a log file), a better approach would be
static long CountLinesInFile(string fileName,string outputFileName)
{
var afp = Path.GetFileNameWithoutExtension(fileName);
uint count = 0;
int query = (int)Convert.ToByte('\n');
using (var stream = File.OpenRead(fileName))
{
int current;
do
{
current = stream.ReadByte();
if (current == query)
{
count++;
continue;
}
} while (current!= -1);
}
using (System.IO.StreamWriter file = new System.IO.StreamWriter(outputFileName, true))
{
file.WriteLine($"AFP|QTY{Environment.NewLine}{afp}|{count}");
}
return count;
}
Update 2
To invoke the method for all files in a given folder, you can make use DirectoryInfo.GetFiles, for example
DirectoryInfo d = new DirectoryInfo(#"E:\TestFolder");
FileInfo[] Files = d.GetFiles("*.txt");
foreach(FileInfo file in Files )
{
CountLinesInFile(file.FullName,$"{file.FullName}.processed");
}
a simple 2 liner
static void CountLines(string path,sting outfile)
{
var count = File.ReadLines(path).Count();
File.WriteAllText(outfile, $"AFP|QTY{Environment.NewLine}DDD|{count}");
}

checking the contents of a text file against a List<string>

So, I am trying to check the contents of a text file to see if any of the values contained within the List textwords exist within the text file.
However when the code is executed it always thinks the message doesn't contain any of the strings contained within the textwords List.
The code used is below.
Any help with this would be greatly appreciated.
List<string> textwords = new List<string>();
using (var UnacceptableWords = new StreamReader("fileLocation"))
{
while (!UnacceptableWords.EndOfStream)
{
string[] row = UnacceptableWords.ReadLine().Split(',');
string Column1 = row[0];
textwords.Add(Column1);
}
}
directory = new DirectoryInfo("filelocation");
files = directory.GetFiles("*.txt");
foreach (FileInfo file in files)
{
using(StreamReader Message = new StreamReader(file.FullName))
{
string MessageContents = Message.ReadToEnd();
if(MessageContents.Contains(textwords.ToString()))
{
MessageBox.Show("found a word");
}
MessageBox.Show("message clean");
}
}
The string.Cointains() method takes in a string but you are passing into it the List, which you have turned into a string.
List.ToString() != Values contained in the List as strings
To do this you must iterate through the array and pass each element of it at a time
foreach(string keyword in textwords)
{
if(MessageContents.Contains(keyword))
{
MessageBox.Show("found a word");
break;
}
}

Why isn't there newline on this file write?

I have written some code to compare 2 files and write their common lines to a 3rd file. For some reason though the 3rd file which contains the common lines has ALL the common lines written to it on 1 line. This should really be 1 new line per common line..I have even tried adding Console.WriteLine('\n'); to add a new line to separate the common lines but this isn't helping. Any ideas as to what is wrong?
//This program will read files and compares to see if they have a line in common
//if there is a line in common then it writes than common line to a new file
static void Main(string[] args)
{
int counter = 0;
string line;
string sline;
string[] words;
string[] samacc = new string[280];
//first file to compare
System.IO.StreamReader sfile =
new System.IO.StreamReader("C:\\Desktop\\autoit\\New folder\\userlist.txt");
while ((sline = sfile.ReadLine()) != null)
{
samacc[counter] = sline;
Console.WriteLine();
counter++;
}
sfile.Close();
//file to write common lines to.
System.IO.StreamWriter wfile = new System.IO.StreamWriter("C:\\Desktop\\autoit\\New folder\\KenUserList.txt");
counter = 0;
//second file to compare
System.IO.StreamReader file =
new System.IO.StreamReader("C:\\Desktop\\autoit\\New folder\\AllUserHomeDirectories.txt");
while ((line = file.ReadLine()) != null)
{
words = line.Split('\t');
foreach (string i in samacc)
{
if (words[0] == i)
{
foreach (string x in words)
{
wfile.Write(x);
wfile.Write('\t');
}
Console.WriteLine('\n');
}
}
}
file.Close();
wfile.Close();
// Suspend the screen.
Console.ReadLine();
}
Change Console.WriteLine('\n'); to wfile.WriteLine('\n');
You can do this in a much better way:
var file1 = File.ReadLines(#"path1");
var file2 = File.ReadLines(#"path2");
var common = file1.Intersect(file2); //returns all lines common to both files
File.WriteAllLines("path3", common);

C# Edit string in file - delete a character (000)

I am rookie in C#, but I need solve one Problem.
I have several text files in Folder and each text files has this structure:
IdNr 000000100
Name Name
Lastname Lastname
Sex M
.... etc...
Load all files from Folder, this is no Problem ,but i need delete "zero" in IdNr, so delete 000000 and 100 leave there. After this file save. Each files had other IdNr, Therefore, it is harder :(
Yes, it is possible each files manual edit, but when i have 3000 files, this is not good :)
Can C# one algorithm, which could this 000000 delete and leave only number 100?
Thank you All.
Vaclav
So, thank you ALL !
But in the End I have this Code :-) :
using System.IO;
namespace name
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Browse_Click(object sender, EventArgs e)
{
DialogResult dialog = folderBrowserDialog1.ShowDialog();
if (dialog == DialogResult.OK)
TP_zdroj.Text = folderBrowserDialog1.SelectedPath;
}
private void start_Click(object sender, EventArgs e)
{
try
{
foreach (string file in Directory.GetFiles(TP_zdroj.Text, "*.txt"))
{
string text = File.ReadAllText(file, Encoding.Default);
text = System.Text.RegularExpressions.Regex.Replace(text, "IdNr 000*", "IdNr ");
File.WriteAllText(file, text, Encoding.Default);
}
}
catch
{
MessageBox.Show("Warning...!");
return;
}
{
MessageBox.Show("Done");
}
}
}
}
Thank you ALL ! ;)
You can use int.Parse:
int number = int.Parse("000000100");
String withoutzeros = number.ToString();
According to your read/save file issue, do the files contain more than one record, is that the header or does each record is a list of key and value like "IdNr 000000100"? It's difficult to answer without these informations.
Edit: Here's a simple but efficient approach which should work if the format is strict:
var files = Directory.EnumerateFiles(path, "*.txt", SearchOption.TopDirectoryOnly);
foreach (var fPath in files)
{
String[] oldLines = File.ReadAllLines(fPath); // load into memory is faster when the files are not really huge
String key = "IdNr ";
if (oldLines.Length != 0)
{
IList<String> newLines = new List<String>();
foreach (String line in oldLines)
{
String newLine = line;
if (line.Contains(key))
{
int numberRangeStart = line.IndexOf(key) + key.Length;
int numberRangeEnd = line.IndexOf(" ", numberRangeStart);
String numberStr = line.Substring(numberRangeStart, numberRangeEnd - numberRangeStart);
int number = int.Parse(numberStr);
String withoutZeros = number.ToString();
newLine = line.Replace(key + numberStr, key + withoutZeros);
newLines.Add(line);
}
newLines.Add(newLine);
}
File.WriteAllLines(fPath, newLines);
}
}
Use TrimStart
var trimmedText = number.TrimStart('0');
This should do it. It assumes your files have a .txt extension, and it removes all occurrences of "000000" from each file.
foreach (string fileName in Directory.GetFiles("*.txt"))
{
File.WriteAllText(fileName, File.ReadAllText(fileName).Replace("000000", ""));
}
These are the steps you would want to take:
Loop each file
Read file line by line
for each line split on " " and remove leading zeros from 2nd element
write the new line back to a temp file
after all lines processed, delete original file and rename temp file
do next file
(you can avoid the temp file part by reading each file in full into memory, but depending on your file sizes this may not be practical)
You can remove the leading zeros with something like this:
string s = "000000100";
s = s.TrimStart('0');
Simply, read every token from the file and use this method:
var token = "000000100";
var result = token.TrimStart('0');
You can write a function similar to this one:
static IEnumerable<string> ModifiedLines(string file) {
string line;
using(var reader = File.OpenText(file)) {
while((line = reader.ReadLine()) != null) {
string[] tokens = line.Split(new char[] { ' ' });
line = string.Empty;
foreach (var token in tokens)
{
line += token.TrimStart('0') + " ";
}
yield return line;
}
}
}
Usage:
File.WriteAllLines(file, ModifiedLines(file));

Categories