I have a program that opens a .txt file and stores it into an array. If the file contains anything other than one number per line than I get an error and the program crashes. I was wondering if there was a way to prevent this from happening and giving the user a message if their file is invalid.
public void Load_Button_Click(object sender, EventArgs e)
{
this.progressBar1.Value = 0; // Reset progress bar
List<int> list = new List<int>();
OpenFileDialog ofd = new OpenFileDialog(); // Initialize open file dialog
ofd.Filter = "TXT File|*.txt"; // Set acceptable files
ofd.Title = "Open File";
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// Open the selected file to read.
string[] lines = File.ReadAllLines(ofd.FileName); // Read all lines in data file selected
dataArray = new int[lines.Length];
for (int i = 0; i < dataArray.Length; ++i)
{
dataArray[i] = int.Parse(lines[i]); // Add data to dataArray array
Unsorted_Box.Text += lines[i] + ", "; // Add data to unsorted box
}// end for
}
}
use int.TryParse():
for (int i = 0; i < dataArray.Length; ++i)
{
if (!int.TryParse(lines[i],out dataArray[i]) // Add data to dataArray array
{
// do something about the invalid data - message / ignore etc..
}
Unsorted_Box.Text += lines[i] + ", "; // Add data to unsorted box
}// end for
Do you know how I would error check this line:
var result2 = text.Split(" \r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)?.Select(num => double.Parse(num)).OrderBy(d => d).ToArray();"
var result2 = text.Split(" \r\n".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries)?.Select(num =>
{
double result;
if (!double.TryParse(num, out result))
{ // error set result to value other than zero if you need to }
return result;
}).OrderBy(d => d).ToArray();"
Related
How to do get the Total lines of the file when we are within in a StreamWriter scope.
Based on the total number of lines count I am writing some more lines at the end of the file.
I have tried the below code : But it throws an error message
The process cannot access the file ‘C:\a.txt ' because it is being used by another process.
var lineCount = File.ReadLines(outputFilePath).Count()
This is my Code
private string CreateAndPushFile(string fileName)
{
string outputFilePath = string.Format(#"{0}\{1}", “C:\\a.txt”, fileName);
using (StreamWriter output = new StreamWriter(outputFilePath))
{
// Creates the file header
string fileHeader =”kjhakljdhkjhkj”;
output.Write(fileHeader);
string batchControl = “1515151”; // This value comes from database
output.Write(batchControl);
// Here there is some other logic which will writes many lines to the File using foreach loop
string fileControl = “3123123”; // This value comes from database
output.WriteLine(fileControl);
// After this I need write a few more lines only if total number of lines in a File Total records multiple of 10
var lineCount = File.ReadLines(outputFilePath).Count(); // I am getting error here
int remainder;
Math.DivRem(lineCount, 10, out remainder);
for (int i = 1; i <= 10 - remainder; i++)
{
output.WriteLine(“9999999999999”);
}
}
}
private static void CreateAndPushFile(string outputFilePath) {
using (var output = new StreamWriter(outputFilePath)) {
// Creates the file header
var fileHeader = "kjhakljdhkjhkj";
output.Write(fileHeader);
var batchControl = "1515151"; // This value comes from database
output.Write(batchControl);
// Here there is some other logic which will writes many lines to the File using foreach loop
var fileControl = "3123123"; // This value comes from database
output.WriteLine(fileControl);
// After this I need write a few more lines only if total number of lines in a File Total records multiple of 10
}
var lineCount = TotalLines(outputFilePath); // I am getting error here
var remainder = lineCount % 10;
using (var output2 = new StreamWriter(outputFilePath, true)) { // second parameter is for append
for (var i = 0; i < 10 - remainder; i++) {
output2.WriteLine("9999999999999");
}
}
}
private static int TotalLines(string filePath) {
using (var reader = new StreamReader(filePath)) {
char[] buffer = new char[1024];
var lineCount = 0;
while (!reader.EndOfStream) {
var charsRead = reader.Read(buffer, 0, 1024);
lineCount += buffer.Take(charsRead).Count(character => character == '\n');
}
return lineCount;
}
}
I am trying to read from each line in a file and grab specific strings and integers. However the values of the found integers are not added up at the end and i'm unsure why. I apologize if this is a simple error.
If a line in the file contains "Event Type: Music", store "Music" in the EventType[] array using MusicTrace. Music trace begins at 0 and increments each time the string above is found. So it works its way down the array. the array size is the amount of lines in the file to ensure there is always enough array space.
I have another Array for attendance named EventAttendance[] which does the same steps above, but cuts the first 18 characters from the found line giving the remaining number (the line in the file is a fixed length). AttendanceTrace is used in the same manner a the above MusicTrace.
I then have a loop for the EventAttendance array which uses i and starts at 0 and carries out code until the EventAttendance.Length property is reached. The code adds up the total attendance from each EventAttendance[] index using i
The code is below:
private void frmActivitiesSummary_Load(object sender, EventArgs e)
{
if (File.Exists(sVenueName.ToString() + ".txt"))
{
using (StreamReader RetrieveEvents = new StreamReader(sVenueName.ToString() + ".txt")) //Create a new file with the name of the username variable
{
string[] ReadLines = File.ReadAllLines(sVenueName + ".txt"); //Read File
int MusicTrace = 0;
int AttendanceTrace = 0;
string[] EventType = new string[ReadLines.Length]; //Store found event types
int[] EventAttendance = new int[ReadLines.Length]; //Store Event Attendance
string line; //Declare String to store line
using (StreamReader file = new StreamReader(sVenueName + ".txt")) //Using StreamReader
{
while (!file.EndOfStream)
{
line = file.ReadToEnd();
//Get All Music Event to Array
if (line.Contains("Event Type: Music"))
{
EventType[MusicTrace] = "Music"; //[0] = Music
if (MusicTrace != 0)
MusicTrace = MusicTrace + 1;
else
MusicTrace = 1;
}
//Get All attendances to Array
if (line.Contains("People Attending:"))
{
line.Remove(0, 18);
int ConvertedLine = Convert.ToInt32(line);
EventAttendance[AttendanceTrace] = ConvertedLine; //[0] = 10
if (AttendanceTrace != 0)
AttendanceTrace = AttendanceTrace + 1;
else
AttendanceTrace = 1;
}
}
}
//for each array index and if array index contains music, add this to total amount of music events
for (int i = 0; i <= EventAttendance.Length; i++)
{
if (EventAttendance[i] > 0)
{
if (iMusicAttendance > 0)
iMusicAttendance = iMusicAttendance + EventAttendance[i];
else
iMusicAttendance = EventAttendance[i];
}
}
}
}
}
The Attendance is then show on the click on a button:
private void btnShow_Click(object sender, EventArgs e)
{
lblMusicOutput.Text = "After analysis, we can see that Music Events have a total attendance of " + iMusicAttendance;
lblArtOutput.Text = "After Analysis, we can see that Events have a total Attenance of " + iArtAttendance;
lblDance.Text = "After Analysis, we can see that Dance Events have a total Attenance of " + iDanceAttendance;
lblTheatreOutput.Text = "After Analysis, we can see that Theatre Events have a total Attenance of " + iTheatreAttendance;
}
There where a several useless variables inside your code, that I took the liberty to remove. I also changed arrays for List<T> in order to use Linq.
You were adding a Convert.ToIn32 with the full line, because String.Remove() doesn't change the object it's called on but return a new string that you have to assign to something : line = line.Remove(0, 18);
Also, you were doing useless checks for the counters:
if (MusicTrace != 0)
MusicTrace = MusicTrace + 1;
else
MusicTrace = 1;
is the same than
MusicTrace++;
which leads us to:
if (!File.Exists(sVenueName.ToString() + ".txt"))
return;
List<String> EventType = new List<string>(); //Store found event types
List<int> EventAttendance = new List<int>(); //Store Event Attendance
using (StreamReader file = new StreamReader(sVenueName + ".txt")) //Using StreamReader
{
while (!file.EndOfStream)
{
var line = file.ReadLine(); //Declare String to store line
//Get All Music Event to Array
if (line.Contains("Event Type: Music"))
{
EventType.Add("Music"); //[0] = Music
}
//Get All attendances to Array
if (line.Contains("People Attending:"))
{
line = line.Remove(0, 18);
EventAttendance.Add(Convert.ToInt32(line)); //[0] = 10
}
}
}
//for each array index and if array index contains music, add this to total amount of music events
iMusicAttendance = EventAttendance.Sum();
Please change :
while (!file.EndOfStream)
{
line = file.ReadToEnd();
to
while (!file.EndOfStream)
{
line = file.ReadLine();
explanation:
You are reading the entire file at once, then you check once your two conditions. But you want to read line by line. So you need to use ReadLine.
As for the rest, you declare but never use the StreamReader RetrieveEvents. You can get rid of it.
You can use List<T> to store the read information. This way you get more flexibility into your code. And the Sum can be calculated without a loop.
EDIT:
I took the liberty to cut down your programm a little. The Code below should do exactly what you describe in your post:
string[] allLines = File.ReadAllLines(sVenueName + ".txt");
List<string> EventType = allLines.Where(x => x.Contains("Event Type: Music"))
.Select(x => x = "Music").ToList();
List<int> EventAttendance = allLines.Where(x => x.Contains("People Attending:"))
.Select(x => Convert.ToInt32(x.Remove(0,18))).ToList();
int iMusicAttendance = EventAttendance.Sum();
EDIT2:
seeing your file content it becomes obvious that you want only to sum up the attending people of the music event, but in your approach you sum up all attending people of all event.
Looking at your file it seems you have an offset of 3 lines. So I would suggest, to get all indices of the Music lines and then grab only the numbers that are 3 lines further:
List<string> allLines = File.ReadAllLines("input.txt").ToList();
List<int> indices = Enumerable.Range(0, allLines.Count)
.Where(index => allLines[index].Contains("Event Type: Music"))
.Select(x => x+=3).ToList();
List<int> EventAttendance = allLines.Where(x => indices.Contains(allLines.IndexOf(x))).Select(x => Convert.ToInt32(x.Remove(0,18))).ToList();
int iMusicAttendance = EventAttendance.Sum();
This will get you the sum of only the music people ;) hop it helps.
I am working on a program where users can upload a textfile with list of links, and after the upload is successful, the lines of the textfile is divided in two listbox where listbox1 contains 50% of the lines in textfile and listbox2 contains remaining 50% .
private void readFile()
{
int linenum = 1;
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Text Files|*.txt";
openFileDialog1.Title = "Select a Text file";
openFileDialog1.FileName = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
string file = openFileDialog1.FileName;
string[] text = System.IO.File.ReadAllLines(file);
foreach (string line in text)
{
if (linenum <= 150)
{
listBox1.Items.Add(line);
}
else
{
listBox2.Items.Add(line);
}
linenum++;
}
}
This code works fine when i know the exact numbers of line in text file, but it throws exception when the textfile consist less line. I am trying to divide the file in two equal parts and show it in two listbox. any advice or suggestion please.
Use the Length-property of the text array. The value of it is equal to the count of members (lines) in the array:
string[] text = System.IO.File.ReadAllLines(file);
int current = 0;
foreach (string line in text)
{
if (current <= text.Length / 2)
{
listBox1.Items.Add(line);
}
else
{
listBox2.Items.Add(line);
}
current++;
}
var textfile = new string[]{"1","2","3","4"};
List<string> listBox1 = new List<string>();
List<string> listBox2 = new List<string>();
listBox1.AddRange(textfile.Take(textfile.Length / 2));
listBox2.AddRange(textfile.Skip(textfile.Length / 2).Take(textfile.Length / 2));
for (int i = 0; i < BackgroundWorkerConfiguration.urlsDirectories.Count; i++)
{
file_array =Directory.GetFiles(BackgroundWorkerConfiguration.urlsDirectories[i]);
}
DateTime[] creationTimes8 = new DateTime[file_array.Length];
for (int i = 0; i < file_array.Length; i++)
creationTimes8[i] = new FileInfo(file_array[i]).CreationTime;
Array.Sort(creationTimes8, file_array);
file_indxs = 0;
file_indxs = file_array.Length - 1;
timer1.Enabled = true;
urlsDirectories contain 5 directories in which you have a directory on each index.
In each directory there are some files. I have a string Array file_array. The Array I get, file_array at the end of the loop only contains the last directory file and not all the files. I need all the files in that specific directory.
Once that is done, I need to check if the file sizes are greater than 0, and if It is satisfying the condition then continue on.
EDIT** this is the timer1 tick event:
private void timer1_Tick(object sender, EventArgs e)
{
try
{
//this.pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
if (leave == true)
{
pb.Load(file_array[file_indxs]);
}
else
{
pbs[0].Load(file_array[file_indxs]);
}
file_indxs = file_indxs - 1;
if (file_indxs < 0)
{
file_indxs = file_array.Length - 1;
}
}
catch
{
timer1.Enabled = false;
}
}
You can use the following code to get the files with size greater than 0 for all directories into a List:
List<System.IO.FileInfo> fileList = new List<System.IO.FileInfo>();
for (int i = 0; i < BackgroundWorkerConfiguration.urlsDirectories.Count; i++)
{
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(BackgroundWorkerConfiguration.urlsDirectories[i]);
fileList.AddRange(di.GetFiles("*.*", System.IO.SearchOption.AllDirectories).Where(x => x.Length > 0));
}
Now fileList will contain the list of FileInfo which you can use further in your code.
Please note that I used System.IO.SearchOption.AllDirectories to search in all subdirectories as well - I'm not sure if you need it or not.
You can use the following code to sort the list of files by creation date and convert it to a array of file names:
String[] file_array = fileList.OrderBy(x => x.CreationTime).Select(x => x.FullName).ToArray();
If you want to sort in the descending order, you can use
String[] file_array = fileList.OrderByDescending(x => x.CreationTime).Select(x => x.FullName).ToArray();
You can make a recursive function that gets the files from a directory.
void GetFiles(string directory, ref List<string> directories)
{
var tempFiles = Directory.EnumerateFiles(directory);
var tempDirs = Directory.EnumerateDirectories(directory);
foreach (var x in tempFiles)
directories.Add(x);
foreach (var x in tempDirs)
GetFiles(x, ref directories);
}
This would obtain all the files from a folder and its subfolders. You can then obtain the data for the files you have enumerated.
I have a C# winform application that is outputting to excel files.
Let's say the name format of the file name is: Output1.xlsl
I would like to have the output saved to another sequential file on each button click/execution.
So next it would be Output2.xlsl, Output3.xlsl... etc.
How to check that, I know of checking if the file exists, but how to check for the numbering?
FileInfo newExcelFile = new FileInfo(#"Output1.xlsx");
if (newExcelFile.Exists)
{
...
}
You could use this loop and File.Exists with Path.Combine:
string directory = #"C:\SomeDirectory";
string fileName = #"Output{0}.xlsx";
int num = 1;
while (File.Exists(Path.Combine(directory, string.Format(fileName, num))))
num++;
var newExcelFile = new FileInfo(Path.Combine(directory, string.Format(fileName, num)));
In general the static File methods are more efficient than always creating a FileInfo instance.
We use a method similar to this to achieve this:
/// <param name="strNewPath">ex: c:\</param>
/// <param name="strFileName">ex: Output.xlsx</param>
/// <returns>Next available filename, ex: Output3.xlsx</returns>
public static string GetValidFileName(string strNewPath, string strFileName)
{
var strFileNameNoExt = Path.GetFileNameWithoutExtension(strFileName);
var strExtension = Path.GetExtension(strFileName);
var intCount = 1;
while (File.Exists(Path.Combine(strNewPath, strFileNameNoExt + intCount + strExtension)))
intCount++;
return Path.Combine(strNewPath, strFileNameNoExt + intCount + strExtension);
}
Just wrap it in a while loop
int num = 1;
FileInfo newExcelFile = new FileInfo("Output1.xlsx");
while(newExcelFile.Exists)
{
newExcelFile = new FileInfo("Output" + num + ".xlsx");
num++;
}
I would find the newest file in the folder and use its number as a basis to start from. If there are no other programs to write there, this should be sufficient.
DirectoryInfo di = new DirectoryInfo("Some folder");
FileInfo fi = di.GetFiles().OrderByDescending(s => s.CreationTime).First();
string fileName = fi.Name;
//....
You can do a simple loop:
FileInfo newExcelFile = null;
for (int i = 0; i < int.MaxValue; i++)
{
newExcelFile = new FileInfo(string.Format(#"Output{0}.xlsx", i));
if (!newExcelFile.Exists)
{
break;
}
newExcelFile = null;
}
if (newExcelFile == null)
{
// do you want to try 2147483647
// or show an error message
// or throw an exception?
}
else
{
// save your file
}
It may not be most efficient one but I can suggest following solution
split the file name with "."
Remove substring "Output" from it
Now sort to get the maximum number.
It depends on the logic. What should happen if you had Output1.xlsx Output2.xlsx Output3.xlsx and removed Output2.xlsx, should the new file be Output2.xlsx or Output4.xlsx?
If you want to have always the highest number for the new files, you can use similar code
int lastNum = 0;
string[] files = Directory.GetFiles("c:\\myDir", "Output*.xlsx");
if (files.Length > 0)
{
Array.Sort(files);
lastNum = Convert.ToInt32(Regex.Match(files[files.Length - 1], "Output[\\d](*).xlsx").Result("$1"));
lastNum++;
}
FileInfo newExcelFile = new FileInfo("Output" + lastNum + ".xlsx");
Of course you can loop, but it's not a good idea if you have thousands of files. For small amount of files it could be fine
int i = 0;
for (; i < Int32.MaxValue; i++)
{
if (File.Exists("Output" + i + ".xlsx"))
break;
}