Read and Write INI file without sections - c#

There is an ini file format
########## Order section ##########
KeyOne=Value1
....
....
....
...
KeyMore=999
Key = 88888*
......
......
......
how can I edit what is behind the = ?
I tried in many ways, but since there are no sections in the ini file, I can’t figure out how to change the values Value1 and 999 and 88888*?
Tried splitting strings with split "=" , but failed to change values. and also add new lines to the file? after Key = 88888*
1.If there are spaces or text in the textbox, then it does not work.
const string filepath = #"C:\Users\123\Desktop\Config.ini";
string text = File.ReadAllText(filepath);
const string PATTERN = #"KeyOne=(?<Number>[\d\.]+)";
Match match = Regex.Match(text, PATTERN, RegexOptions.IgnoreCase);
if (match.Success)
{
int index = match.Groups["Number"].Index;
int length = match.Groups["Number"].Length;
text = text.Remove(index, length);
text = text.Insert(index, Program.form1.textBox11.Text);
File.WriteAllText(filepath, text);
}

An INI file has a well defined structure composed by one or many [Sections] and zero or many pairs of [Key]=[Value] under each section. A file without at least a section is not a proper INI file and the standard windows API GetPrivateProfileString and WritePrivateProfileString are not able to read a file with that format.
However, your file is a lot simpler than a standard INI file. It is just composed by pairs of [Key]=[Value] so it is a naturally perfect fit for a Dictionary<string, string>
Reading it coud be simple as
Dictionary<string, string> GetConfigData(string fileName)
{
Dictionary<string, string> data = new Dictionary<string, string>();
foreach (string line in File.ReadLines(fileName))
{
var lineData = line.Split('=');
data.Add(lineData[0], lineData[1]);
}
return data;
}
and writing back that dictionary is even simpler
void WriteConfigData(string fileName, Dictionary<string, string> data)
{
File.WriteAllLines(fileName, data.Select(z => $"{z.Key}={z.Value}{Environment.NewLine}"));
}
Now if you want to change some value you could have
var data = GetConfigData("yourbadinifile.ini");
data["KeyValue"] = "a new value";
WriteConfigData("yourbadinifile.ini", data);
Warning: In the examples above there is no error checking. A robust solution should check if the file passed to the read method exists and if the split operation produces an array of two elements. Consider also that checking for binary files is also an unhandled problem and with complex solutions. So we could also consider to let exceptions bubble up to the client caller.

Related

Reading CSV file having Field name in each line?

I am working in an ERP integration software. I need to parse CSV file from HRM application to make an entry.
I am getting the input CSV file like this:
$Emp.No$=123456,$CardNo$=254658,$InTime$="12/11/2013 09:03:05",$OutTime$="12/11/2013 17:25:20"
$Emp.No$=565556,$CardNo$=254689,$InTime$="12/11/2013 09:03:50",$OutTime$="12/11/2013 18:01:11"
The CSV file doesn't have a column name header, instead each field has a field name associated with it inside $FieldName$.
I tried to parse it with CSVHelper. It just works fine, when using ReadFieldsByIndex() method.
Problem:
Some of the columns do not have $InTime$ or $OutTime$. So, reading by index fails. How can I read only available data and how to map according to the field name available in each line.
You haven't got a CSV file there. You have a data file, each line of which contains one or more key/value pairs, separated by commas. The key and value are separated by an = and the key is enclosed by $'s.
Having expressed what you have, that should help you identify a solution:
Don't use a CSV framework.
Read each line at a time from the file.
Split the line on , to give you the key value pairs.
Split the key value pairs on = to give the two parts.
(Optionally) remove the $ from the key name.
You then should have a suitable level of data to transfer these values into whatever destination objects you have.
This will write to the separate file with headers and followed by values.
string file =#"D:\STACKOVERFLOW\csvproblem.txt";
string newfile =#"D:\STACKOVERFLOW\output.txt";
StreamReader sr = new StreamReader(file);
StreamWriter sw = new StreamWriter(newfile);
try{
string header = "";
StringBuilder sb = new StringBuilder();
StringBuilder sb_header = new StringBuilder();
bool recordHeader = true;
while(sr.EndOfStream==false){
string readLine = sr.ReadLine();
string[] split = readLine.Split(',');
sb = new StringBuilder();
foreach (string str in split)
{
if (recordHeader)
{
if (str.IndexOf('$') < str.LastIndexOf('$'))
{
sb_header.AppendFormat("{0},",
str.Substring(str.IndexOf('$'),str.IndexOf('$')+str.LastIndexOf('$')+1));
}
}
sb.AppendFormat("{0},", str.Substring(str.IndexOf('=')+1));
}
if (recordHeader)
{
sw.WriteLine(sb_header.ToString().Trim(','));
}
sw.WriteLine(sb.ToString().Trim(','));
recordHeader = false;
}
}
finally{
sr.Close();
sw.Close();
}

Convert a tab delimited file into CSV file in c# [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to covert tab separated file to CSV file
i have a tab delimited text file which i have to convert into CSV file all this must be done through C# code. My txt file is very large about(1.5 GB), hence i want to convert it in a quick time. please help me.
If your input tab delimited text file does not have any commas are part of the data, then it is a very straightforward find and replace similar to the other answers here:
var lines = File.ReadAllLines(path);
var csv= lines.Select(row => string.Join(",", row.Split('\t')));
File.WriteAllLines(path, csv);
But if your data has commas, doing this is going to break your columns as you now have extra commas that are not supposed to be delimiters, but will be interpreted as such. How to handle it depends greatly on what you application you will be using to read the CSV.
A Microsoft Excel compatible CSV is going to have double quotes around fields with commas to make sure they are interpreted as data and not a delimiter. This also means that fields that contain double quotes as data will need special treatment.
I would recommend a similar approach with an extension method.
var input = File.ReadAllLines(path);
var lines = input.Select(row => row.Split('\t'));
lines = lines.Select(row => row.Select(field => field.EscapeCsvField(',', '"')).ToArray());
var csv = lines.Select(row => string.Join(",", row));
File.WriteAllLines(path, csv.ToArray());
And here's the EscapeCsvField extension method:
static class Extension
{
public static String EscapeCsvField(this String source, Char delimiter, Char escapeChar)
{
if (source.Contains(delimiter) || source.Contains(escapeChar))
return String.Format("{0}{1}{0}", escapeChar, source);
return source;
}
}
Also, if the file is large, it might be best to not read the entire file into memory. In that case, I would suggest writing the CSV output to a different file and then you could use StreamReader and StreamWriter to only work with it 1 line at a time.
var tabPath = path;
var csvPath = Path.Combine(
Path.GetDirectoryName(path),
String.Format("{0}.{1}", Path.GetFileNameWithoutExtension(path), "csv"));
using (var sr = new StreamReader(tabPath))
using (var sw = new StreamWriter(csvPath, false))
{
while (!sr.EndOfStream)
{
var line = sr.ReadLine().Split('\t').Select(field => field.EscapeCsvField(',', '"')).ToArray();
var csv = String.Join(",", line);
sw.WriteLine(csv);
}
}
File.Delete(tabPath);
var csv = File.ReadAllLines("Path").Select(line => line.Replace("\t", ","));
You could simply call
public void ConvertToCSV(string strPath, string strOutput)
{
File.WriteAllLines(strOutput, File.ReadAllLines("Path").Select(line => line.Replace("\t", ",")));
}
There is a lot of content already on SO for handling .CSV files, please search first or trying something.
If the format of your file is strict, you could use string.Split and string.Join:
var lines = File.ReadAllLines(path);
var newLines = lines.Select(l => string.Join(",", l.Split('\t')));
File.WriteAllLines(path, newLines);

Searching strings in txt file

I have a .txt file with a list of 174 different strings. Each string has an unique identifier.
For example:
123|this data is variable|
456|this data is variable|
789|so is this|
etc..
I wish to write a programe in C# that will read the .txt file and display only one of the 174 strings if I specify the ID of the string I want. This is because in the file I have all the data is variable so only the ID can be used to pull the string. So instead of ending up with the example about I get just one line.
eg just
123|this data is variable|
I seem to be able to write a programe that will pull just the ID from the .txt file and not the entire string or a program that mearly reads the whole file and displays it. But am yet to wirte on that does exactly what I need. HELP!
Well the actual string i get out from the txt file has no '|' they were just in the example. An example of the real string would be: 0111111(0010101) where the data in the brackets is variable. The brackets dont exsist in the real string either.
namespace String_reader
{
class Program
{
static void Main(string[] args)
{
String filepath = #"C:\my file name here";
string line;
if(File.Exists(filepath))
{
StreamReader file = null;
try
{
file = new StreamReader(filepath);
while ((line = file.ReadLine()) !=null)
{
string regMatch = "ID number here"; //this is where it all falls apart.
Regex.IsMatch (line, regMatch);
Console.WriteLine (line);// When program is run it just displays the whole .txt file
}
}
}
finally{
if (file !=null)
file.Close();
}
}
Console.ReadLine();
}
}
}
Use a Regex. Something along the lines of Regex.Match("|"+inputString+"|",#"\|[ ]*\d+\|(.+?)\|").Groups[1].Value
Oh, I almost forgot; you'll need to substitute the d+ for the actual index you want. Right now, that'll just get you the first one.
The "|" before and after the input string makes sure both the index and the value are enclosed in a | for all elements, including the first and last. There's ways of doing a Regex without it, but IMHO they just make your regex more complicated, and less readable.
Assuming you have path and id.
Console.WriteLine(File.ReadAllLines(path).Where(l => l.StartsWith(id + "|")).FirstOrDefault());
Use ReadLines to get a string array of lines then string split on the |
You could use Regex.Split method
FileInfo info = new FileInfo("filename.txt");
String[] lines = info.OpenText().ReadToEnd().Split(' ');
foreach(String line in lines)
{
int id = Convert.ToInt32(line.Split('|')[0]);
string text = Convert.ToInt32(line.Split('|')[1]);
}
Read the data into a string
Split the string on "|"
Read the items 2 by 2: key:value,key:value,...
Add them to a dictionary
Now you can easily find your string with dictionary[key].
first load the hole file to a string.
then try this:
string s = "123|this data is variable| 456|this data is also variable| 789|so is this|";
int index = s.IndexOf("123", 0);
string temp = s.Substring(index,s.Length-index);
string[] splitStr = temp.Split('|');
Console.WriteLine(splitStr[1]);
hope this is what you are looking for.
private static IEnumerable<string> ReadLines(string fspec)
{
using (var reader = new StreamReader(new FileStream(fspec, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
while (!reader.EndOfStream)
yield return reader.ReadLine();
}
}
var dict = ReadLines("input.txt")
.Select(s =>
{
var split = s.Split("|".ToArray(), 2);
return new {Id = Int32.Parse(split[0]), Text = split[1]};
})
.ToDictionary(kv => kv.Id, kv => kv.Text);
Please note that with .NET 4.0 you don't need the ReadLines function, because there is ReadLines
You can now work with that as any dictionary:
Console.WriteLine(dict[12]);
Console.WriteLine(dict[999]);
No error handling here, please add your own
You can use Split method to divide the entire text into parts sepparated by '|'. Then all even elements will correspond to numbers odd elements - to strings.
StreamReader sr = new StreamReader(filename);
string text = sr.ReadToEnd();
string[] data = text.Split('|');
Then convert certain data elements to numbers and strings, i.e. int[] IDs and string[] Strs. Find the index of the given ID with idx = Array.FindIndex(IDs, ID.Equals) and the corresponding string will be Strs[idx]
List <int> IDs;
List <string> Strs;
for (int i = 0; i < data.Length - 1; i += 2)
{
IDs.Add(int.Parse(data[i]));
Strs.Add(data[i + 1]);
}
idx = Array.FindIndex(IDs, ID.Equals); // we get ID from input
answer = Strs[idx];

C#: Read data from txt file

I have an .EDF (text) file. The file's contents are as follows:
ConfigFile.Sample, Software v0.32, CP Version 0.32
[123_Float][2]
[127_Number][0]
[039_Code][70]
I wnat to read these items and parse them like this:
123_Float - 2
127_Number - 0
039_Code - 70
How can I do this using C#?
Well, you might start with the File.ReadAllLines() method. Then, iterate through the lines in that file, checking to see if they match a pattern. If they do, extract the necessary text and do whatever you want with it.
Here's an example that assumes you want lines in the format [(field 1)][(field 2)]:
// Or wherever your file is located
string path = #"C:\MyFile.edf";
// Pattern to check each line
Regex pattern = new Regex(#"\[([^\]]*?)\]");
// Read in lines
string[] lines = File.ReadAllLines(path);
// Iterate through lines
foreach (string line in lines)
{
// Check if line matches your format here
var matches = pattern.Matches(line);
if (matches.Count == 2)
{
string value1 = matches[0].Groups[1].Value;
string value2 = matches[1].Groups[1].Value;
Console.WriteLine(string.Format("{0} - {1}", value1, value2));
}
}
This outputs them to the console window, but you could obviously do whatever you want with value1 and value2 (write them to another file, store them in a data structure, etc).
Also, please note that regular expressions are not my strong point -- there's probably a much more elegant way to check if a line matches your pattern :)
If you want more info, check out MSDN's article on reading data from a text file as a starting point.
Let us assume your file really is as simple as you describe it. Then you could drop the first line and parse the data lines like this:
foreach (string line in File.ReadAllLines(#"C:\MyFile.edf").Skip(1))
{
var parts = line.Split("][");
var value1 = parts[0].Replace("[", "");
var value2 = parts[1].Replace("]", "");
Console.WriteLine(string.Format("{0} - {1}", value1, value2));
}
Another variation.
var lines = File.ReadAllLines(file)
.Skip(1)
.Select(x => x.Split(new[] { '[', ']' },
StringSplitOptions.RemoveEmptyEntries));
foreach(var pair in lines)
{
Console.WriteLine(pair.First()+" - "+pair.Last());
}

Reading ini file in C#

I am trying to read an ini file that has the following format:
SETTING=VALUE
SETTING2=VALUE2
I currently have the following code:
string cache = sr.ReadToEnd();
string[] splitCache = cache.Split(new string[] {"\n", "\r\n"}, StringSplitOptions.RemoveEmptyEntries);
Which gives me a list of settings, however, what I would like to do is read this into a dictionary. My question is, is there a way to do this without iterating through the entire array and manually populating the dictionary?
Well, you could use LINQ and do
Dictionary<string, string> ini = (from entry in splitCache
let key = entry.Substring(0, entry.FirstIndexOf("="))
let value = entry.Substring(entry.FirstIndexOf("="))
select new { key, value }).ToDictionary(e => e.key, e => e.value);
As Binary Worrier points out in the comments, this way of doing this has no advantages over the simple loop suggested by the other answers.
Edit: A shorter version of the block above would be
Dictionary<string, string> ini = splitCache.ToDictionary(
entry => entry.Substring(0, entry.FirstIndexOf("="),
entry => entry.Substring(entry.FirstIndexOf("="));
What is wrong with iterating?
var lines = File.ReadAllLines("pathtoyourfile.ini");
var dict = new Dictionary<string, string>();
foreach(var s in lines)
{
var split = s.Split("=");
dict.Add(split[0], split[1]);
}
There's actually a Windows API for reading/writing INI files in kernel32.dll; see this CodeProject article for an example.
INI files are a bit tricky so I wouldn't recommend rolling your own. I wrote Nini which is a configuration library that includes a very fast parser.
Sample INI file:
; This is a comment
[My Section]
key 1 = value 1
key 2 = value 2
[Pets]
dog = rover
cat = muffy
Same C# code:
// Load the file
IniDocument doc = new IniDocument ("test.ini");
// Print the data from the keys
Console.WriteLine ("Key 1: " + doc.Get ("My Section", "key 1"));
Console.WriteLine ("Key 2: " + doc.Get ("Pets", "dog"));
// Create a new section
doc.SetSection ("Movies");
// Set new values in the section
doc.SetKey ("Movies", "horror", "Scream");
doc.SetKey ("Movies", "comedy", "Dumb and Dumber");
// Remove a section or values from a section
doc.RemoveSection ("My Section");
doc.RemoveKey ("Pets", "dog");
// Save the changes
doc.Save("test.ini");
Try like this
[DllImport("kernel32.dll", EntryPoint = "GetPrivateProfileString")]
public static extern int GetPrivateProfileString(string SectionName, string KeyName, string Default, StringBuilder Return_StringBuilder_Name, int Size, string FileName);
and call the function like this
GetPrivateProfileString(Section_Name, "SETTING", "0", StringBuilder_Name, 10, "filename.ini");
Value can be accessed from StringBuilder_Name.
Why not read the file as separate lines, then loop over them splitting on the first =?
var dict = new Dictionary<string,string>();
foreach (var line in File.ReadAllLines(filename)) {
var parts = line.Split('=', 2); // Maximum of 2 parts, so '=' in value ignored.
dict.Add(parts[0], parts[1]);
}
(In .NET 4 replace ReadAllLines with ReadLines, to avoid creating the array, ReadLines returns IEnumerable<String> and reads the file lazily.)

Categories

Resources