I have a problem reading data from a CSV file. As in the following example I try to read in the list information from two different columns. With the query "EndOfStream" or with a count variable larger than about 6000 I get the error: "The index was out of range". However, with a count variable of 4000, the code works exactly as it should. I do not understand my mistake.
List<string> gpsGGA = new List<string>();
List<string> gpsRMC = new List<string>();
public Form1()
{
InitializeComponent();
}
private void btn_file_Click(object sender, EventArgs e)
{
string path;
OpenFileDialog file = new OpenFileDialog();
if (file.ShowDialog() == DialogResult.OK)
{
try {
path = file.FileName;
StreamReader data = new StreamReader(path);
data.ReadLine(); //Header verwerfen
gpsGGA.Clear();
gpsRMC.Clear();
for(int i=0; i<8000; i++)//while (!data.EndOfStream)
{
string[] substring = data.ReadLine().Split(';');
gpsGGA.Add(substring[11]);
gpsRMC.Add(substring[12]);
}
data.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Not sure why this is commented out:
for(int i=0; i<8000; i++)//while (!data.EndOfStream)
The while loop that is commented out intended to only read data while exists.
I added a using statement to ensure the file gets closed. I added an IsNullOrEmpty check in case there's a blank line at the end of the file, so you don't get an error with that.
using (StreamReader data = new StreamReader(path))
{
data.ReadLine(); //Header verwerfen
gpsGGA.Clear();
gpsRMC.Clear();
int counter = 0;
while (!data.EndOfStream)
{
string line = data.ReadLine();
if (! String.IsNullOrEmpty(line))
{
string[] substring = line.Split(';');
if ( substring.Length < 13 )
throw new ApplicationException("Malformated Data At Line " + counter.ToString());
gpsGGA.Add(substring[11]);
gpsRMC.Add(substring[12]);
}
counter += 1;
}
}
Your codes makes it hard to guess wheter the error is coming from reading the file or the file content itself.
You can use File.ReadAllLines which takes the file path and returns its lines as an array, regardless of the number of lines that you specify in the foor loop, which by the way can cause errors if the number of lines is is not equal to 8000.
if (file.ShowDialog() == DialogResult.OK)
{
try
{
gpsGGA.Clear();
gpsRMC.Clear();
string[] lines= File.ReadAllLines(file.FileName);
foreach(String line in lines)
{
string[] substring = line.Split(';');
gpsGGA.Add(substring[11]);
gpsRMC.Add(substring[12]);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The index was out of range is probably caused by some lines which have invalid data
For example this is line 6000 : sdd;dfdf;dfdf;00;dfdf;555
When you try to get element at index 11 or 12, it doesn't exist because this line has only 6 elements
Related
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)
So I have a generic number check that I am trying to implement:
public static bool isNumberValid(string Number)
{
}
And I want to read the contents of a textfile (only contains numbers) and check each line for the number and verify it is the valid number using isNumberValid. Then I want to output the results to a new textfile, I got this far:
private void button2_Click(object sender, EventArgs e)
{
int size = -1;
DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
if (result == DialogResult.OK) // Test result.
{
string file = openFileDialog1.FileName;
try
{
string text = File.ReadAllText(file);
size = text.Length;
using (StringReader reader = new StringReader(text))
{
foreach (int number in text)
{
// check against isNumberValid
// write the results to a new textfile
}
}
}
catch (IOException)
{
}
}
}
Kind of stuck from here if anyone can help?
The textfile contains several numbers in a list:
4564
4565
4455
etc.
The new textfile I want to write would just be the numbers with true or false appended to the end:
4564 true
You don't need to read the entire file into memory all at once. You can write:
using (var writer = new StreamWriter(outputPath))
{
foreach (var line in File.ReadLines(filename)
{
foreach (var num in line.Split(','))
{
writer.Write(num + " ");
writer.WriteLine(IsNumberValid(num));
}
}
}
The primary advantage here is a much smaller memory footprint, as it only loads a small part of the file at a time.
You could try this to keep with the pattern you were initially following...
private void button1_Click(object sender, EventArgs e)
{
DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog.
if (result == DialogResult.OK) // Test result.
{
string file = openFileDialog1.FileName;
try
{
using (var reader = new StreamReader(file))
{
using (var writer = new StreamWriter("results.txt"))
{
string currentNumber;
while ((currentNumber = reader.ReadLine()) != null)
{
if (IsNumberValid(currentNumber))
writer.WriteLine(String.Format("{0} true", currentNumber));
}
}
}
}
catch (IOException)
{
}
}
}
public bool IsNumberValid(string number)
{
//Whatever code you use to check your number
}
You need to replace your loop to look like this:
string[] lines = File.ReadAllLines(file);
foreach (var s in lines)
{
int number = int.Parse(s);
...
}
This would read each line of file, assuming that there is only one number per line,
and lines are separated with CRLF symbols. And parse each number to integer, assuming that integer is not greater than 2,147,483,647 and not less than -2,147,483,648, and integers are stored in your locale settings, with or without group separators.
In case if any line is empty, or contains non-integer - code will throw an exception.
You could try something like this:
FileStream fsIn = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
using (StreamReader sr = new StreamReader(fsIn))
{
line = sr.ReadLine();
while (!String.IsNullOrEmpty(line)
{
line = sr.ReadLine();
//call isNumberValid on each line, store results to list
}
}
Then print the list using FileStream.
As other people have mentioned, your isNumberValid method could make use of the Int32.TryParse method, but since you said your text file only contains numbers this may not be necessary. If you're just trying to match the number exactly, you can use number == line.
First, load all lines of the input file in a string array,
then open the output file and loop over the array of strings,
Split each line at the space separator and pass every part to your static method.
The static method use Int32.TryParse to determine if you have a valid integer or not without throwing an exception if the input text is not a valid Int32 number.
Based on the result of the method write to the output file the desidered text.
// Read all lines in memory (Could be optimized, but for this example let's go with a small file)
string[] lines = File.ReadAllLines(file);
// Open the output file
using (StringWriter writer = new StringWriter(outputFile))
{
// Loop on every line loaded from the input file
// Example "1234 ABCD 456 ZZZZ 98989"
foreach (string line in lines)
{
// Split the current line in the wannabe numbers
string[] numParts = line.Split(' ');
// Loop on every part and pass to the validation
foreach(string number in numParts)
{
// Write the result to the output file
if(isNumberValid(number))
writer.WriteLine(number + " True");
else
writer.WriteLine(number + " False");
}
}
}
// Receives a string and test if it is a Int32 number
public static bool isNumberValid(string Number)
{
int result;
return Int32.TryParse(Number, out result);
}
Of course this works only if your definition of 'number' is equal to the allowed values for a Int32 datatype
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));
i am reading information from a text file and i want to go through the text file row by row and in each row i want to split each sentence from the other based on a character(eg. ',') and i want to save the data in an array but when i print it i am getting just the last result.
private void button1_Click_1(object sender, EventArgs e)
{
string StringArray = null;
//to get the browsed file and get sure it is not curropted
try
{
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
using (StreamReader sr = new StreamReader(openFileDialog1.FileName))
{
string data;
while ((data = sr.ReadLine()) != null)
{
StringArray = data.Split(',');
}
}
for (int i = 0; i < StringArray.Length; i++)
{
textBox1.Text = StringArray[i];
}
FilePath.Text = openFileDialog1.FileName;
textBox1.Text = (string)File.ReadAllText(FilePath.Text);
}
}
catch(IOException ex)
{
MessageBox.Show("there is an error" + ex+ "in the file please try again");
}
}
Here is your error:
Above you define:
string StringArray = null;
Then later you use it as:
StringArray = information.ToString().Split(SplitCommas);
Split returns string[] not string. you need to change the declaration at the top to..
string[] StringArray;
The error: "cannot implicitly convert a type string[] to string". should give you the hint that you are trying to store a string array into a string.
You need to define StringArray as a String[]
string[] StringArray = null;
You might be better off using String.Split instead of the for loop
StringArray = data.Split(',');
In your 3rd line you a declaring String array as a string, you should declare it as an array:
string [] StringArray = null;
Working on an application to parse robots.txt. I wrote myself a method that pulled the the file from a webserver, and threw the ouput into a textbox. I would like the output to display a single line of text for every line thats in the file, just as it would appear if you were looking at the robots.txt normally, however the ouput in my textbox is all of the lines of text without carriage returns or line breaks. So I thought I'd be crafty, make a string[] for all the lines, make a foreach loop and all would be well. Alas that did not work, so then I thought I would try System.Enviornment.Newline, still not working. Here's the code as it sounds now....how can I change this so I get all the individual lines of robots.txt as opposed to a bunch of text cobbled together?
public void getRobots()
{
WebClient wClient = new WebClient();
string url = String.Format("http://{0}/robots.txt", urlBox.Text);
try
{
Stream data = wClient.OpenRead(url);
StreamReader read = new StreamReader(data);
string[] lines = new string[] { read.ReadToEnd() };
foreach (string line in lines)
{
textBox1.AppendText(line + System.Environment.NewLine);
}
}
catch (WebException ex)
{
MessageBox.Show(ex.Message, null, MessageBoxButtons.OK);
}
}
You are reading the entire file into the first element of the lines array:
string[] lines = new string[] {read.ReadToEnd()};
So all your loop is doing is adding the whole contents of the file into the TextBox, followed by a newline character. Replace that line with these:
string content = read.ReadToEnd();
string[] lines = content.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
And see if that works.
Edit: an alternative and perhaps more efficient way, as per Fish's comment below about reading line by line—replace the code within the try block with this:
Stream data = wClient.OpenRead(url);
StreamReader read = new StreamReader(data);
while (read.Peek() >= 0)
{
textBox1.AppendText(read.ReadLine() + System.Environment.NewLine);
}
You need to make the textBox1 multiline. Then I think you can simply go
textBox1.Lines = lines;
but let me check that
Try
public void getRobots()
{
WebClient wClient = new WebClient();
string robotText;
string[] robotLines;
System.Text.StringBuilder robotStringBuilder;
robotText = wClient.DownloadString(String.Format("http://{0}/robots.txt", urlBox.Text));
robotLines = robotText.Split(Environment.NewLine);
robotStringBuilder = New StringBuilder();
foreach (string line in robotLines)
{
robotStringBuilder.Append(line);
robotStringBuilder.Append(Environment.NewLine);
}
textbox1.Text = robotStringBuilder.ToString();
}
Try using .Read() in a while loop instead of .ReadToEnd() - I think you're just getting the entire file as one line in your lines array. Debug and check the count of lines[] to verify this.
Edit: Here's a bit of sample code. Haven't tested it, but I think it should work OK;
Stream data = wClient.OpenRead(url);
StreamReader read = new StreamReader(data);
List<string> lines = new List<string>();
string nextLine = read.ReadLine();
while (nextLine != null)
{
lines.Add(nextLine);
nextLine = read.ReadLine();
}
textBox1.Lines = lines.ToArray();