I'm trying to get rid of if-else statements in my function, so I don't need to specify every drive possible. In this case I'm reading a .csv file. Is there any way to avoid the struggle of if-else.
Thanks in advance!
My code now:
if (str == "(D:)")
{
csvPath = #"D:\file1.CSV";
try
{
using (var fs = File.Open(csvPot, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var csvFileDescription = new CsvFileDescription
{
FirstLineHasColumnNames = true,
IgnoreUnknownColumns = true,
SeparatorChar = ',',
UseFieldIndexForReadingData = false
};
var csvContext = new LINQtoCSV.CsvContext();
var settings = csvContext.Read<Settings>(csvPot, csvFileDescription);
foreach (var setting in settings)
{
tbx_ssid.Text = setting.SSID;
tbx_pass.Text = setting.password;
}
if (tbx_ssid.Text == "" && tbx_pass.Text == "")
{
MessageBox.Show("No data!");
}
}
}
catch (FileNotFoundException)
{
MessageBox.Show("File not exsists!");
}
}
else if (str == "(E:)")
{
.
.
.
You could prepare a Dictionary<string, string> where the key is the drive to use and the value is the filepath to retrieve the file.
Something like this.
Dictionary<string, string> fileToUse = new Dictionary<string, string>();
fileToUse.Add("(D:)", #"D:\file1.CSV");
fileToUse.Add("(E:)", #"E:\someotherfolder\file1.CSV");
Now it is simply a matter of
if (fileToUse.TryGetValue(str, out string file))
{
// Code that uses _file_
}
Another approach is to strip from the str string the opening and closing parenthesys and use the string cleared for a substitution of the first two characters of the filepath
string noPar = str.Trim('(', ')');
string baseFile = #"\file1.CSV";
string fullFile = $"{noPar}{baseFile}";
With this approach however you are forced to have that file in the root folder of the drive choosen (or in some fixed location). Not always the best choice in the long term.
SimonC solved my question. It works for me perfect !
csvPath = $#"{str}/file1.csv";
Related
I have a text file containing some information that I want to edit. The file looks something like this:
id: 31
name: Anna
profession: Doctor
I can read that entry with a StreamReader, and present it in my application. I then want the user to be able to change the name and profession of an entry, so I'd like to edit these specific rows to the new values, while keeping id intact (in my real code, there's not just a few rows, but a lot of rows where only some should be changed). So, for example, I want the file, at the end of my operation, to look like this.
id: 31
name: Emma
profession: Programmer
However, I also have to take into account that sometimes the rows don't exist beforehand. For example, before editing Anna to Emma, it's not certain that she had a profession, the file could have looked like this:
id: 31
name: Anna
And in that case, I want to add the line profession: Programmerto the end there.
I tried using a FileStreamwith ReadWrite access, that I give to a StreamReader and a StreamWriter, but then I found no way of changing or replacing a line of text, only reading it and writing a new identical line while keeping the old.
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite))
using (StreamReader reader = new StreamReader(fileStream))
using (StreamWriter writer = new StreamWriter(fileStream))
{
bool idExists = false;
bool nameExists = false;
bool tagsExist = false;
string line;
while((line = reader.ReadLine()) != null)
{
if (line.StartsWith("id:"))
idExists = true;
else if (line.StartsWith("name:"))
{
nameExists = true;
line = $"name: {entryToSave.Name}";
writer.WriteLine(line); // Will write an additional line and not replace
}
else if (line.StartsWith("profession:"))
{
professionExists = true;
line = $"profession: {entryToSave.Profession}";
writer.WriteLine(line); // Will write an additional line and not replace
}
}
if (!idExists)
writer.WriteLine($"id: {generatedId}");
if (!nameExists)
writer.WriteLine($"name: {entryToSave.Name}");
if (!professionExists)
writer.WriteLine($"profession: {entryToSave.Profession}");
}
I also tried using File.ReadAllLines, loop through the lines, and then write back all the lines to the file, only modifying the lines that were to be modified. However, I don't have access to the file through File.WriteAllLines for some reason that I don't understand, as a StreamWriter has access. Code:
var previousData = File.ReadAllLines(filePath);
var newData = new List<string>();
bool idExists = false;
bool nameExists = false;
bool professionExists = false;
for (int i = 0; i < previousData.Length; i++)
{
var line = previousData[i];
if (line.StartsWith("id:")
idExists = true;
else if (line.StartsWith("name:")
{
nameExists = true;
line = $"name: {entryToSave.Name}";
}
else if (line.StartsWith("profession:"))
{
professionExists = true;
line = $"profession: {entryToSave.Profession}";
}
newData.Add(line);
}
if (!idExists)
newData.Add($"id: {generatedId}");
if (!nameExists)
newData.Add($"name: {entryToSave.Name}");
if (!professionExists)
newData.Add($"profession: {entryToSave.Profession}");
File.WriteAllLines(filePath, newData.ToArray()); // Access denied
How is this most easily achieved, without file streams interfering with each other?
If you've already presented the data to the user in entries, enabling the user to edit name and profession, you could just read the file, get the ID and fill the remainder of the file with the value of the entries. The following is an example console application.
static void Main(string[] args)
{
var filePath = "test.txt";
// Simulated input from user
// these should come from entries in the application?
var name = "Foo";
var profession = "Bar";
var personData = new PersonData(); // class declared below
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite))
using (StreamReader reader = new StreamReader(fileStream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line.StartsWith("id:"))
personData.ID = line;
}
} // Now reader and filestream is closed, file is available again.
// You don't specify what you would like to happen if personData.ID is null,
// so I make an assumption the generatedId is what you'd like to use.
if (string.IsNullOrWhiteSpace(personData.ID)
personData.ID = $"id: {generatedId}";
// Add the data from the entries
personData.Name = $"name: {name}";
personData.Profession = $"profession: {profession}";
File.Delete(filePath); // remove the file
using (FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
using (StreamWriter writer = new StreamWriter(fileStream))
{
writer.WriteLine(personData.ID);
writer.WriteLine(personData.Name);
writer.WriteLine(personData.Profession);
}
}
private class PersonData
{
public string ID { get; set; }
public string Name { get; set; }
public string Profession { get; set; }
}
Now you just have to find out how to get access to the file if you're having permission problems.
I have file.txt like:
EDIT: I didn't wrote but this is important i guess- In file.txt there can be others lines!
folder=c:\user;c:\test;c:\something;
I need to add one path like one list item (List<string> Folders).
So my List should looks like:
Folders[0] = c:\user
Folders[1] = c:\test
etc. (without text "folder=" which starts line in file.txt and ";" which means end of path).
file can contain much more paths.
I did something like this:
using (FileStream fss = new FileStream(path, FileMode.Open))
{
using (StreamReader sr = new StreamReader(fss))
{
while (sr.EndOfStream == false)
{
string line = sr.ReadLine();
if(line.StartsWith("folders"))
{
int index = line.IndexOf("=");
int index1 = line.IndexOf(";");
string folder = line.Substring(index + 1, index1 - (index + 1));
Folders.Add(folder);
Now in List Folders i have first path but what now? I can't go ahead :(
using(var sr = new StreamReader(path))
{
var folders = sr.ReadToEnd()
.Split(new char[]{';','\n','\r'}, StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.Replace("folder=",""))
.ToArray();
Folders.AddRange(folders);
}
You can try following code, using File.ReadAllText
string Filepath = "c:\abc.txt";
string filecontent = File.ReadAllText(Filepath);
string startingString = "=";
var startIndex = filecontent.IndexOf(startingString);
filecontent = filecontent.Substring(startIndex + 1, filecontent.Length - startIndex - 2);
List<String> folders = filecontent.Split(';').ToList();
Here's a simple example:
List<String> Folders = new List<string>();
private void button1_Click(object sender, EventArgs e)
{
string path = #"C:\Users\mikes\Documents\SomeFile.txt";
string folderTag = "folder=";
using (FileStream fss = new FileStream(path, FileMode.Open))
{
using (StreamReader sr = new StreamReader(fss))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
if (line.StartsWith(folderTag))
{
line = line.Substring(folderTag.Length); // remove the folderTag from the beginning
Folders.AddRange(line.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries));
}
}
}
}
foreach(string folder in Folders)
{
Console.WriteLine(folder);
}
}
I'd use this approach if you're going to read line by line, and do something else based on what each line starts with. In that case you could add different else if(...) blocks:
if (line.StartsWith(folderTag))
{
line = line.Substring(folderTag.Length); // remove the folderTag from the beginning
Folders.AddRange(line.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries));
}
else if(line.StartsWith("parameters="))
{
// do something different with a line starting with "parameters="
}
else if (line.StartsWith("unicorns="))
{
// do something else different with a line starting with "unicorns="
}
I need to check certain columns of data to make sure there are no trailing blank spaces. At first thought I thought it would be very easy, but after attempting to achieve the goal I have got stuck.
I know that there should be 6-digits in the column I need to check. If there is less I will reject, if there are more I will trim the blank spaces. After doing that for the entire file, I want to write it back to the file with the same delimiters.
This is my attempt:
Everything seems to be working correctly except for writing the file.
if (File.Exists(filename))
{
using (StreamReader sr = new StreamReader(filename))
{
string lines = sr.ReadLine();
string[] delimit = lines.Split('|');
while (delimit[count] != "COLUMN_DATA_TO_CHANGE")
{
count++;
}
string[] allLines = File.ReadAllLines(#filename);
foreach(string nextLine in allLines.Skip(1)){
string[] tempLine = nextLine.Split('|');
if (tempLine[count].Length == 6)
{
checkColumn(tempLine);
writeFile(tempLine);
}
else if (tempLine[count].Length > 6)
{
tempLine[count] = tempLine[count].Trim();
checkColumn(tempLine);
}
else
{
throw new Exception("Not enough numbers");
}
}
}
}
}
public static void checkColumn(string[] str)
{
for (int i = 0; i < str[count].Length; i++)
{
char[] c = str[count].ToCharArray();
if (!Char.IsDigit(c[i]))
{
throw new Exception("A non-digit is contained in data");
}
}
}
public static void writeFile(string[] str)
{
string temp;
using (StreamWriter sw = new StreamWriter(filename+ "_tmp", false))
{
StringBuilder builder = new StringBuilder();
bool firstColumn = true;
foreach (string value in str)
{
if (!firstColumn)
{
builder.Append('|');
}
if (value.IndexOfAny(new char[] { '"', ',' }) != -1)
{
builder.AppendFormat("\"{0}\"", value.Replace("\"", "\"\""));
}
else
{
builder.Append(value);
}
firstColumn = false;
}
temp = builder.ToString();
sw.WriteLine(temp);
}
}
If there is a better way to go about this, I would love to hear it. Thank you for looking at the question.
edit:
file structure-
country| firstname| lastname| uniqueID (column I am checking)| address| etc
USA|John|Doe|123456 |5 main street|
notice the blank space after the 6
var oldLines = File.ReadAllLines(filePath):
var newLines = oldLines.Select(FixLine).ToArray();
File.WriteAllLines(filePath, newLines);
string FixLine(string oldLine)
{
string fixedLine = ....
return fixedLine;
}
The main problem with writing the file is that you're opening the output file for each output line, and you're opening it with append=false, which causes the file to be overwritten every time. A better approach would be to open the output file one time (probably right after validating the input file header).
Another problem is that you're opening the input file a second time with .ReadAllLines(). It would be better to read the existing file one line at a time in a loop.
Consider this modification:
using (StreamWriter sw = new StreamWriter(filename+ "_tmp", false))
{
string nextLine;
while ((nextLine = sr.ReadLine()) != null)
{
string[] tempLine = nextLine.Split('|');
...
writeFile(sw, tempLine);
I Am using sharp develop. I am making a Win App using C# . I want my program check a text file named test in drive c: and find the line which contains "=" and then write this line to other newly created text file in drive c: .
Try this one-liner:
File.WriteAllLines(destinationFileName,
File.ReadAllLines(sourceFileName)
.Where(x => x.Contains("=")));
Here's another simple way using File.ReadLines, Linq's Where and File.AppendAllLines
var path1 = #"C:\test.txt";
var path2 = #"C:\test_out.txt";
var equalLines = File.ReadLines(path1)
.Where(l => l.Contains("="));
File.AppendAllLines(path2, equalLines.Take(1));
using(StreamWriter sw = new StreamWriter(#"C:\destinationFile.txt"))
{
StreamReader sr = new StreamReader(#"C:\sourceFile.txt");
string line = String.Empty;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("=")) { sw.WriteLine(line)); }
}
sr.Close();
}
Have you tried something?
Here are two ways to read a file:
Use static methods available in File class. ReadAllLines to be specific. This is good enough if you are dealing with small files. Next, once you have the array, just find the item with "=" using LINQ or by any other iteration method. Once you got the line, again use File class to create and write data to the file.
If you are dealing with large files, use Stream. Rest remains fairly same.
if (File.Exists(txtBaseAddress.Text))
{
StreamReader sr = new StreamReader(txtBaseAddress.Text);
string line;
string fileText = "";
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("="))
{
fileText += line;
}
}
sr.Close();
if (fileText != "")
{
try
{
StreamWriter sw = new StreamWriter(txtDestAddress.Text);
sw.Write(fileText);
sw.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
a bit edited Furqan's answer
using (StreamReader sr = new StreamReader(#"C:\Users\Username\Documents\a.txt"))
using (StreamWriter sw = new StreamWriter(#"C:\Users\Username\Documents\b.txt"))
{
int counter = 0;
string line = String.Empty;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("="))
{
sw.WriteLine(line);
if (++counter == 4)
{
sw.WriteLine();
counter = 0;
}
}
}
}
i have this code that compares two text files and write the difference to a log file but for some reason the log.txt file is some times blank even when is test with some lines starting with a * these are not always written either do I have to save the text file when finished writing although this does not explain why sometimes it works any help would be great
private void compare()
{
string FilePath = #"c:\snapshot\1.txt";
string Filepath2 = #"c:\snapshot\2.txt";
int counter = 0;
string line;
string line2;
var dir = "c:\\snapshot\\log.txt";
using (FileStream fs = File.Create(dir))
{
fs.Dispose();
}
StreamWriter dest = new StreamWriter(dir);
if (File.Exists(FilePath) & File.Exists(Filepath2))
{
// Read the file and display it line by line.
using (var file = File.OpenText(FilePath))
using (var file2 = File.OpenText(Filepath2))
{
while (((line = file.ReadLine()) != null & (line2 = file2.ReadLine()) != null))
{
if (line.Contains("*"))
{
dest.WriteLine(line2);
}
else if (!line.Contains(line2))
{
dest.WriteLine(line2);
}
counter++;
}
}
}
dest.Close();
}
Everything left in the buffer should be written out once you hit the close statement on your StreamReader. If you are missing stuff then it might be that you aren't reaching that line for some reason (i.e. you crash). Also, if you are trying to look at the file while it's being written (i.e. while the program is still running), you won't necessarily see everything (since it hasn't closed).
Generally, it's better to use a using statement with the StreamReader. That should ensure that it always gets closed.
private void compare()
{
string FileName1 = #"c:\snapshot\1.txt";
string FileName2 = #"c:\snapshot\2.txt";
string FileNameOutput = #"c:\snapshot\log.txt"; //dir ???
int counter = 0; // um what's this for you aren't using it.
using (FileStream fso = new FileStream(FileNameOutput, FileMode.Create, FileAccess.Write))
{
TextWriter dest = new StreamWriter(fso);
using(FileStream fs1 = new FileStream(FileName1, FileMode.Open, FileAccess.Read))
{
using (FileStream fs2 = new FileStream(FileName2, FileMode.Open, FileAccess.Read))
{
TextReader firstFile = new StreamReader(fs1);
TextReader secondFile = new StreamReader(fs2);
while (((line1 = firstFile.ReadLine()) != null & (line2 = secondFile.ReadLine()) != null))
{
if ((line1.Contains("*") || (!line1.Contains(line2)))
{
dest.Write(line2); // Writeline would give you an extra line?
}
counter++; //
}
}
}
fso.Flush();
}
I commend the overloads of FileStream to you. Do it the way I have and the code will crash at the point you instance the stream if the user running it doesn't have all the required permissions. It's a nice way of showing what you intend, and what you don't.
PS You do know contains is case and culture sensitive?
Not sure if I'm understanding your comparing logic right, but as long as I separated comparing from whole code you can adjust it to your own needs:
public static void WriteDifferences(string sourcePath, string destinationPath, string differencesPath)
{
var sourceLines = File.ReadAllLines(sourcePath).ToList();
var destinationLines = File.ReadAllLines(destinationPath).ToList();
// make lists equal size
if (sourceLines.Count > destinationLines.Count)
{
destinationLines.AddRange(Enumerable.Range(0, sourceLines.Count - destinationLines.Count).Select(x => (string)null));
}
else
{
sourceLines.AddRange(Enumerable.Range(0, destinationLines.Count - sourceLines.Count).Select(x => (string)null));
}
var differences = sourceLines.Zip(destinationLines, (source, destination) => Compare(source, destination));
File.WriteAllLines(differencesPath, differences.Where(x => x != null));
}
private static string Compare(string source, string destination)
{
return !source.Contains(destination) || source.Contains("*") ? destination : null;
}