I am working on selecting a text file with a folder pathway via a Windows form in C# and gathering information on each pathway. At the minute, I can import the file and display only the second pathway in the text file, but no information on the folder. Here is the code I have:
private void btnFilePath_Click(object sender, EventArgs e)
{
//creating a stream and setting its value to null
Stream myStream = null;
//allowing the user select the file by searching for it
OpenFileDialog open = new OpenFileDialog();
open.InitialDirectory = "c:\\";
open.Filter = "txt files (*.txt)|*.txt";
open.FilterIndex = 2;
open.RestoreDirectory = true;
//if statement to print the contents of the file to the text box
if (open.ShowDialog() == DialogResult.OK)
{
try
{
if ((myStream = open.OpenFile()) != null)
{
using (myStream)
{
txtFilePath.Text = string.Format("{0}", open.FileName);
if (txtFilePath.Text != "")
{
lstFileContents.Text = System.IO.File.ReadAllText(txtFilePath.Text);
//counting the lines in the text file
using (var input = File.OpenText(txtFilePath.Text))
{
while (input.ReadLine() != null)
{
//getting the info
lstFileContents.Items.Add("" + pathway);
pathway = input.ReadLine();
getSize();
getFiles();
getFolders();
getInfo();
result++;
}
MessageBox.Show("The number of lines is: " + result, "");
lstFileContents.Items.Add(result);
}
}
else
{
//display a message box if there is no address
MessageBox.Show("Enter a valid address.", "Not a valid address.");
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read the file from disk. Original error: " + ex.Message);
}
}
}
I was thinking that copying each line to a variable using a foreach or putting each line into an array and looping through it to gather the information.
Can anyone advise me which would be most suitable so I can go to MSDN and learn for myself, because, I'd prefer to learn it instead of being given the code.
Thanks!
I am not sure what your question is since you seemed to have answered it. If you want us to review it you question would be better suited to Code Review: https://codereview.stackexchange.com/
If you want to use MSDN look here: http://msdn.microsoft.com/en-us/library/System.IO.File_methods(v=vs.110).aspx
Spoiler alert, here is how I would do it:
string[] lines = null;
try
{
lines = File.ReadAllLines(path);
}
catch(Exception ex)
{
// inform user or log depending on your usage scenario
}
if(lines != null)
{
// do something with lines
}
to just gather all lines into array i would use
var lines = File.ReadAllLines(path);
If you want to have more reference rather than the answer itself, take these links one by one all of them explaining things in different manner.
C# File.ReadLines
How to: Read From a Text File (C# Programming Guide)
How to: Read a Text File One Line at a Time (Visual C#)
Hope it will help you to learn more about File IO operations in C#.
Related
I am new to working with System.IO.
I have an application that grabs a Json file from the web and only grabs partial data to display on the Windows Application Form's controls.
The form allows the user to save the data as a new file and load a file if ONLY it contains the "indicator" I added in when the file was saved that tells the program it was saved by my program.
Everything works.
Whenever a file that doesn't contain that indicator is loaded to the program, it doesn't show nothing which is what I want it to do, but I also want a Messagebox.Show() to pop up and let the user know why the values are empty and why nothing happened.
if(openFile.ShowDialog() == DialogResult.OK)
{
string dataLine = string.Empty;
using (StreamReader read = new StreamReader(File.OpenRead(openFile.FileName)))
{
dataLine = read.ReadToEnd();
string[] beginningOfData = dataLine.Split(',');
string temporary = string.Empty;
foreach (string line in beginningOfData)
{
//Indicator
if(line.Contains("Indicator")
{
temporary = line.substring(9);
//Goes through the rest of the file
//Converts data to control value and adds it
}
else
{
//Where I tried to display the message box
}
}
}
}
This what I've tried, but it wasn't working as I wanted it too
else
{
MessageBox.Show("Can't load data.");
}
It would still show the MessageBox even if it read that the indicator was there and displayed the data inside the corresponding controls. Also whenever I tried to close the MessageBox it would just show it again.
So I decided to this instead:
else if(!line.contains("Indicator"))
{
MessageBox.Show("Can't load data.");
break;
}
and in this way too:
else
{
if(!line.contains("Indicator"))
{
MessageBox.Show("Can't load data.");
break;
}
}
I also tried making it more specific by doing
if(line.contains("Indicator") == false)
{
//Code here
}
But it would still display it even if the file was created by the program.
The break; did stop the message box from re-appearing again, but I only want the MessageBox to show when it's the incorrect text file (not containing the indicator) and allow me to close the MessageBox to try again.
You can wrap the foreach into an if statement which will use some LINQ code to determine if all lines contain "indicator":
if (beginningOfData.All(line => line.ToLower().Contains("indicator")))
{
string temporary = string.Empty;
foreach (string line in beginningOfData)
{
temporary = line.Substring(9);
//Goes through the rest of the file
//Converts data to control value and adds it
}
}
else
{
System.Windows.Forms.MessageBox.Show("Can't load data.");
}
Contains is case-sensitive. Try this for your evaluation:
line.IndexOf("Indicator", StringComparison.InvariantCultureIgnoreCase) >= 0
I did this instead and it worked for my application
if(openFile.ShowDialog() == DialogResult.OK)
{
string dataLine = string.Empty;
using (StreamReader read = new StreamReader(File.OpenRead(openFile.FileName)))
{
//Changed happened here
dataLine = read.ReadToEnd();
string[] beginningOfData = dataLine.Split(',');
string temporary = string.Empty;
if(beginningOfData.Contains("Indicator"))
{
temporary = dataLine.Substring(9);
foreach(string realData in beginningOfData)
{
//Goes through file
}
}
else
{
MessageBox.Show("Can't load data");
}
}
}
I'm writing a simple WinForms application which I will use prior to when I edit my video footage in order to know the total length of all the video files when combined and "edited".
So ideally, I load them up then get the duration of each video and tally them up.
However I get stuck in terms of which collection class to use since I am using an external library IWMPMedia in addition to WindowsMediaPlayer to get the filenames and duration.
When I use a string array to get the filename, I get the whole path, which is something I don't want. Please see the following code snippet:
using WMPLib;
public partial class frmBacklinkMediaSerializer : Form
{
WindowsMediaPlayer wmp;
IWMPMedia mediainfo;
Double Duration(String file)
{
wmp = new WindowsMediaPlayer();
mediainfo = wmp.newMedia(file);
return mediainfo.duration;
}
void callDialogBox()
{
OpenFileDialog theDialog = new OpenFileDialog();
theDialog.Filter = "MP4 Videos (*.mp4)|*.mp4";
theDialog.FilterIndex = 0;
theDialog.Multiselect = true;
DialogResult result = theDialog.ShowDialog();
string[] selected = theDialog.FileNames;
string strFilename = theDialog.FileName;
if (result == DialogResult.OK)
{
FileInfo oFileInfo = new FileInfo(strFilename);
string temp = Duration(strFilename).ToString();
TimeSpan conversion =
TimeSpan.FromSeconds(Duration(strFilename));
if (strFilename != null || strFilename.Length != 0)
{
MessageBox.Show("My file names are below: " + "\n\n" + mediainfo.name + "\n\n" + "My file duration is: " + conversion.ToString(), "Video Properties", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
}
}
//I then call callDialogBox() on a button click event
The output shows as per the below screenshot:
I want to be able to select multiple files and show the in the listbox but I get a:
Additional information: COM object that has been separated from its underlying RCW cannot be used.
When adding items to the listbox.
So two problems:
1. Being able to select and list filenames below one another
2. List the filenames in the listbox
With regards to point 1. , the below code snippet does somewhat achieve it but gives me the entire filename..
string[] selected = theDialog.FileNames;
foreach(string items in selected)
{
MessageBox.Show("Here are your filenames: " + items);
}
Gives me the entire path. Read up on some resources online but I can't seem to get what I want.
I had a look at: How do I drag n drop files into a ListBox with it showing the file path? and it didn't do the trick.
Try the following to add the filenames to the ListBox:
listBox1.Items.AddRange(selected);
Once this is done, you can then display your total duration.
Edit:
To list only file names, use following line.
listBox1.Items.AddRange(selected.Select(o=>System.IO.Path.GetFileName(o)).ToArray());
I have read a lot of answers on this issue, but none of them helps for me.
Now, it's been 5 years that I had C# and apperantly I've forgotten it all. But I like to get into the language again to use it for automation. So, here is the bit of code I already have:
{
string path = #"C:\Users\decraiec\Documents\Client Automated";
//In this folder I will find all my XML files that I just want to load in a textbox
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//create a way to read and write the files
//go get the files from my harddrive
StreamReader FileReader = new StreamReader(path);
//make something readable for what you have fetched
StreamWriter FileWriter = new StreamWriter(textBox1.ToString());
int c = 0;
while (c == FileReader.Read())
{
string load = FileReader.ReadToEnd();//read every xmlfile up to the end
string stream = FileWriter.ToString();//make something readable
}
try
{
textBox1.Text = FileWriter.ToString();//what you have made readable, show it in the textbox
FileWriter.Close();
}
finally
{
if (FileReader != null)
{ FileReader.Close(); }
}
if (FileWriter != null)
{ FileWriter.Close(); }
}
}
If I run this code like this I'll get:
An unhandled exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll
Additional information: Access to the path 'C:\Users\decraiec\Documents\Atrias Automated' is denied.
While I was hoping to see all the XML files in the textbox listed and clickable ( - although I need to insert the clickable code yet )
I've been looking in my folder and subfolder and files and I do have admin rights on everything. About the [ mscorlib.dll ] I have no clue where to find this.
Now if I wrap the StreamReader in a use ( var....;) VS doesn't recognizes it (red lines under the words) saying that I'm missing an instance of an object or something else of issue (just trying to glue the things together).
Could someone try to get me in the right direction please?
I think your path is a directory, not a file. Almost the exact same issue was addressed here: Question: Using Windows 7, Unauthorized Access Exception when running my application
What you can do is create a DirectoryInfo object on the path and then call GetFiles on it. For example:
DirectoryInfo di = new DirectoryInfo(directoryPath);
Foreach(var file in di.GetFiles())
{
string pathToUseWithStreamReader = file.FullName;
}
You need to use Directory.GetFiles to get any files residing in your "Client Automated" folder, then loop through them and load every single file into the stream.
var files = Directory.GetFiles(path);
foreach (var file in files)
{
var content = File.ReadAllText(file);
}
You can read more on it here:
https://msdn.microsoft.com/en-us/library/07wt70x2(v=vs.110).aspx
Also - in general, when working with files or directories like this, it's a good idea to programmatically check if they exist before working with them. You can do it like so:
if (Directory.Exists(path))
{
...
}
Or with files:
if (File.Exists(path))
{
...
}
Really new to C#. I need to search a text file for a keyword. If after the whole file is searched, the keyword is found pop a message box. If after the whole file is searched, the keyword is NOT found pop a message box.
So far I have this below. The problem is that it reads the file line by line. If in the first line the keyword is not found it shows the alert "Not found". Then goes to the next line and shows "Not found" again. And so on. I need the script to search the whole file, and only then show "Not found" only once. Thank you!
private void SearchButton_Click(object sender, EventArgs e)
{
System.IO.StreamReader file = new System.IO.StreamReader("c:\\test.txt");
String line;
String[] array;
while ((line = file.ReadLine()) != null)
{
if (line.Contains("keyword"))
{
MessageBox.Show("Keyword found!");
}
else
{
MessageBox.Show("Keyword not found!");
}
}
}
Try using File class instead of readers (which you have to Dispose in order to prevent resource leakage):
bool found = File
.ReadLines("c:\\test.txt") // Try avoid "All" when reading: ReadAllText, ReadAllLines
.Any(line => line.Contains("keyword"));
if (found)
MessageBox.Show("Keyword found!");
else
MessageBox.Show("Keyword not found!");
Your code amended (if you insist on StreamReader):
private void SearchButton_Click(object sender, EventArgs e) {
// Wra IDisposable (StreamReader) into using in order to prevent resource leakage
using (file = new StreamReader("c:\\test.txt")) {
string line;
while ((line = file.ReadLine()) != null)
if (line.Contains("keyword")) {
MessageBox.Show("Keyword found!");
return; // Keyword found, reported and so we have nothing to do
}
}
// File read with no positive result
MessageBox.Show("Keyword not found!");
}
File.ReadAllText is better suited for that, you can read in all the text at once in one string:
string file = File.ReadAllText("path");
if (file.Contains(keyword)) {
//..
}
else {
//..
}
or in one line:
if (File.ReadAllText("path").Contains("path")) {
}
else {
}
Like stated in the comments, you can run out of memory for very large files but for normal day to day use this wont happen.
I have a program where the user can add products to the system, and then search them by the product name.
Everything is working fine, except at the moment is able to enter two products with the same name. I need the program to not allow this.
I have a method assigned to the 'Add' button, which saves the product name, customer name and firmware location to a text file. Here is that method:
private void button_Click(object sender, RoutedEventArgs e)
{
bool found = false;
string searchTerm = productNameTextBox.Text.ToUpper();
if ((productNameTextBox.Text == "") || (customerNameTextBox.Text == "") || (firmwareLocationTextBox.Text == ""))
{
MessageBox.Show("Please fill in all the text boxes");
}
else if (Contains(searchTerm) == true)
{
MessageBox.Show("Product already added");
}
else
{
string inputCustomerName = customerNameTextBox.Text.ToUpper();
string inputProductName = productNameTextBox.Text.ToUpper();
string inputFirmwareLocation = firmwareLocationTextBox.Text;
try
{
Product newProduct = new Product(inputProductName, inputCustomerName, inputFirmwareLocation);
newProduct.Save("Products.txt");
File.AppendAllText("ProductNames.txt", inputProductName + Environment.NewLine);
MessageBox.Show("Product added");
emptyTheTextBoxes();
}
catch
{
MessageBox.Show("Product could not be added");
}
}
}
I have also made a method which will search a text file to see if the users product name has already been stored, and then return a Boolean. This is the method:
public bool Contains (string searchTerm)
{
string line;
bool found = false;
System.IO.StreamReader file = new System.IO.StreamReader("ProductNames.txt");
while ((line = file.ReadLine()) != null)
{
if (line.Contains(searchTerm))
{
found = true;
break;
}
}
if (found == true)
{
return true;
}
else
{
return false;
}
file.Close();
}
When I try to save the input, a message box appears saying "Product could not be added". However, if I comment out the else if statement which calls the method, it works fine.
I thought it may be because I open the file when the method is called, and maybe it wasn't closing properly. So I added the 'file.Close()' and it hasn't made a difference.
I feel like I've just made a silly mistake somewhere, but its been bugging me for hours! Definitely appreciate a fresh pair of eyes!
Thanks
Lucy
In general I would suggest that you separate out your persistence of objects from your object/data management.
You are trying to read and write to the filesystem for the same file in different parts of the program and it seems like you are having an issue with the file not being released, probably because you didn't close it correctly.
You are trying to treat the file system as if it is a database, and this is probably not the best approach. There are of course use cases where this might be needed.
Instead I would suggest the following approach.
During start up read the file. Load the products into a collection
which you keep in memory.
Allow your program to read, update, create, delete products in the
collection.
During shutdown (can also be triggered manually if you want), save
your products onto disk.
This will allow you to avoid such issues. And also be quicker.
Optionally you could also then use something like HashSet<T> for your collection. This does not allow duplicate entries (remember to override equals and hashcode in your Product object). Then when trying to add to the collection if it returns false then it was not added, which would indicate a duplicate. So this might make it easier and quicker to check for you.
I had the file.close() in the wrong place. Here is where I moved it to:
public bool Contains (string searchTerm)
{
string line;
bool found = false;
System.IO.StreamReader file = new System.IO.StreamReader("ProductNames.txt");
while ((line = file.ReadLine()) != null)
{
if (line.Contains(searchTerm))
{
found = true;
break;
}
}
file.Close();
if (found == true)
{
return true;
}
else
{
return false;
}
}