Getting an index outside bound of an array in C# - c#

This program is supposed to show the path of a directory and the directory if its exists then it should also show the files inside with the following extensions (i.e .doc, .pdf, .jpg, .jpeg) but I'm getting an error
*Index was outside the bounds of the array.
on this line of code
string directoryPath = args[0];
This is the code in the main function
class Program
{
static void Main(string[] args)
{
string directoryPath = args[0];
string[] filesList, filesListTmp;
IFileOperation[] opList = { new FileProcNameAfter10(),
new FileProcEnc(),
new FileProcByExt("jpeg"),
new FileProcByExt("jpg"),
new FileProcByExt("doc"),
new FileProcByExt("pdf"),
new FileProcByExt("djvu")
};
if (Directory.Exists(directoryPath))
{
filesList = Directory.GetFiles(directoryPath);
while (true)
{
Thread.Sleep(500);
filesListTmp = Directory.GetFiles(directoryPath);
foreach (var elem in Enumerable.Except<string>(filesListTmp, filesList))
{
Console.WriteLine(elem);
foreach (var op in opList)
{
if (op.Accept(elem)) op.Process(elem);
}
}
filesList = filesListTmp;
if (Console.KeyAvailable == true && Console.ReadKey(true).Key == ConsoleKey.Escape) break;
}
}
else
{
Console.WriteLine("There is no such directory.");
}
}
}
How can I handle this error it seems to be common but it happens id different ways

You need to pass the necessary arguments to the program when running it. You can either do this by running the program from the command line, or else when running Visual Studio by doing the following:
Right click on project
Properties
Debug tag
Enter arguments under Start Options -> Command line arguments

You might want to pass the arguments into the program from command line.
like this:
> yourProgram.exe directoryName
Also, to avoid such problems in the code,
if(args.Length > 0){
string directoryPath = args[0];
}else{
//print a help message and exit, or do something like set the
//default directoryPath to current directory
}

Do you want the user to enter a path when the program starts or when they start the program? If it's the first, then you should add a Console.Read() method that asks for the path.
If it's the latter, then you need to pass the path as an argument when starting the program. You should also do a check against the args array before reading from it to check that it contains data and that data is a valid path.
Something like:
if(args.Length > 0 && Directory.Exists(args[0]))
{
// Do Something.
}

Related

How can i get all files on disk with a specific extension using 'Directory.getFiles' and save them in a list

I'm doing a console project whose goal is to search the entire disk for all files with the extension '.config'
I've tried something like:
foreach (string file in Directory.GetFiles("C:\\", "*.config", SearchOption.AllDirectories))
{
Console.WriteLine(file);
Console.ReadLine();
}
but gave me an error "denied access to path (...)".
On the internet I found this code:
Stack<string> pending = new Stack<string>();
pending.Push("C:\\");
while (pending.Count != 0)
{
var path = pending.Pop();
string[] next = null;
try
{
next = Directory.GetFiles(path, "*.config");
}
catch { }
if (next != null && next.Length != 0)
foreach (var file in next)
{
Console.WriteLine(file);
Console.ReadLine();
}
try
{
next = Directory.GetDirectories(path);
foreach (var subdir in next) pending.Push(subdir);
}
catch { }
}
but it just shows the path clicking always in 'enter' and I want to save those files/path in a list.
Someone can help?
There are two things you can do to improve that code:
Use Directory.EnumerateFiles() and Directory.EnumerateDirectories() to avoid making a copy of the names of all the files in each directory.
Make the return type of the method IEnumerable<string> to make it easier to consume.
We also need to be very careful about exceptions caused by attempting to access protected files and directories. The code below is also complicated by the fact that you're not allowed to yield return from inside a try/catch block, so we have to rearrange the code somewhat.
(Also note that we have to dispose the enumerator returned from .GetEnumerator(); normally this is done automatically when you use foreach, but in this case we can't - because of having to avoid doing yield return in a try/catch - so we have to use using to dispose it.)
Here's a modification of your original code to do this:
public static IEnumerable<string> GetFiles(string root, string spec)
{
var pending = new Stack<string>(new []{root});
while (pending.Count > 0)
{
var path = pending.Pop();
IEnumerator<string> fileIterator = null;
try
{
fileIterator = Directory.EnumerateFiles(path, spec).GetEnumerator();
}
catch {}
if (fileIterator != null)
{
using (fileIterator)
{
while (true)
{
try
{
if (!fileIterator.MoveNext()) // Throws if file is not accessible.
break;
}
catch { break; }
yield return fileIterator.Current;
}
}
}
IEnumerator<string> dirIterator = null;
try
{
dirIterator = Directory.EnumerateDirectories(path).GetEnumerator();
}
catch {}
if (dirIterator != null)
{
using (dirIterator)
{
while (true)
{
try
{
if (!dirIterator.MoveNext()) // Throws if directory is not accessible.
break;
}
catch { break; }
pending.Push(dirIterator.Current);
}
}
}
}
}
As an example, here's how you could use a console app to list all the accessible ".txt" files on the "C:\" drive:
static void Main()
{
foreach (var file in GetFiles("C:\\", "*.txt"))
{
Console.WriteLine(file);
}
}
Replace the lines
Console.WriteLine(file);
Console.ReadLine();
with a method to store them in a list.
For example
foundFiles.Add(file);
Then when the method is done, you can read all found file paths from this list.
Notes:
This will not yield all files on the system that match the filter.
Only files where your application has access to their respective directory are found this way.
For example the Windows directory and user directories of other users are usually protected. (assuming you run on Windows)
Keep in mind, that some files might be protected independently of their directory.
So when trying to read them, also consider the fact, that the read might fail.
Just encompass the read with a try catch.
Regarding the error "denied access to path (...)", sometimes you have to run Visual Studio as an a administrator in order to access some folders in the C:\ drive.

Checking to see File exists is not working

I am trying to check to see if the file exists if it doesn't leave the textbox blank! it doesn't work
string[] filePaths = Directory.GetFiles(#"C:\TwinTable\LeftTableO0201", "*.*");
if (!File.Exists(filePaths.ToString()))
{
TboxLeftTable.Text = "";
}
else
{
TboxLeftTable.Text = System.IO.Path.GetFileName(filePaths[0]);
}
Well, one problem you have is that you are just trying to use ToString() on an array. Since Directory.GetFiles() returns an array of file names, you need to iterate over those files and check them one at a time. Something like this:
string[] filePaths = Directory.GetFiles(#"C:\TwinTable\LeftTableO0201", "*.*");
foreach (string curFilePath in filePaths)
{
if (!File.Exists(curFilePath))
{
TboxLeftTable.Text = "";
}
else
{
TboxLeftTable.Text = System.IO.Path.GetFileName(curFilePath);
}
}
Once your code is fixed you still have weird logic. If we take your logic and spell it out in a sentence it reads like this:
Get a list of files from a folder, then immediately check to see if the file(s) in that folder exist
I think what you want to do instead is:
Get a list of files from a folder, if one exists display the very first one's name in a textbox, if it does not, display nothing
If I am right, then your code would look like this:
// Gets all string file paths in a folder
// then grabs the first one, or null if there are none
string filePath = Directory.GetFiles(#"C:\TwinTable\LeftTableO0201", "*.*").FirstOrDefault();
// if the path is not null, empty or whitespace
if(!string.IsNullOrWhiteSpace(filePath)
{
// then get the filename and put it in the textbox
TboxLeftTable.Text = Path.GetFileName(filePath);
}
else
{
// There were no files in the folder so make the textbox empty
TboxLeftTable.Text = string.Empty;
}
This is the working code. Thanks for the help!
string[] filePaths = Directory.GetFiles(#"C:\TwinTable\LeftTableO0201", "*.*");
if (filePaths.Length > 0)
TboxLeftTable.Text = System.IO.Path.GetFileName(filePaths[0]);

Multiple command line inputs

I am having a bit of trouble running multiple conditions through a command line argument. I have a program that makes XML files based on information found in Excel files. The main issue i am having is that when i run the program through an auto scheduling tool it reads each file as a one whole string, instead of "File 1" "File 2" it is reading it as "File1File2". This is the code for the command line:
public static void Main(string[] args)
{
string input = "";
string output = "";
if (args.Length > 0)
{
foreach (string s in args)
{
Console.WriteLine(s);
}
input = args[0];
output = args[1];
}
}
I wondered if there was a way, im aware of methods such as split string but the implementation is what i am fuzzy on

Read multiple .txt files at once with console command

Hi I'm programing a console application that reads in the text of a .txt file and then calculates the Flesch Score (how easy a text is to read). It's already able to get started by the console by typing in the path and some parameters f.e. -f "filename" or -e for english. Now I want to read in multiple textfiles with the command -f "testfile*.txt. The * means that it doesn't matter what is written after f.e. enumeration. How can I achieve that with a console command? Correct me if I'm wrong with something I'm kind of new to programing :)
Here's how I am doing it:
string[] parameters = new string[] { "-f", "-e", "-g" };
Flesch_Reading_Ease.FleschScore.Language lang = FleschScore.Language.Undefined;
string filename = "";
foreach (string arg in args)
{
switch (arg.Trim().ToLower())
{
case "-e":
lang = Flesch_Reading_Ease.FleschScore.Language.English;
break;
case "-g":
lang = Flesch_Reading_Ease.FleschScore.Language.German;
break;
case "-f":
break;
default:
{
if (File.Exists(arg))
filename = arg;
}
break;
}
}
If you use the Directory.GetFiles method it will return a list of files that match the wildcard:
string[] files = Directory.GetFiles(folder, arg);
where folder is the name of the directory you're looking in. You'll either have to assume the current folder "." or split the path from the input arguments.
You can then loop over this list:
foreach (var file in files)
{
// Do your processing
}

Passing parameters from one app to the other

Following on from this thread Starting application before target application
I have an application which gets passed a parameter (a filename) and does some registry work before opening Microsoft InfoPath.
I need to open InfoPath with the parameter that was passed to the original application.
Here is how I open InfoPath
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.Arguments = ConvertArrayToString(Constants.Arguments);
//prc.StartInfo.Arguments = "hello";
prc.StartInfo.FileName = Constants.PathToInfoPath;
prc.Start();
Note that when I set the Arguments to "hello" InfoPath pops up a message saying cannot find file "hello" however when I set it Constants.Arguments I get an error and Windows asks me if I want to debug or close the applicatiion.
Here is how I set Constants.Arguments in the Main(string[] args)
static void Main(string[] args)
{
Constants.Arguments = args;
//...
}
And here is ConvertArrayToString
private string ConvertArrayToString(string[] arr)
{
string rtn = "";
foreach (string s in arr)
{
rtn += s;
}
return rtn;
}
I suppose the format of the parameter is causing the error, any idea why?
The value of Arguments after being stringed is
c:\users\accountname\Desktop\HSE-000403.xml
Edit:
Thanks to N K's answer.
The issue is in order for my application to open when InfoPath files are opened, I have changed the name of INFOPATH.EXE to INFOPATH0.EXE and my application is called INFOPATH.EXE and is in the InfoPath folder, so when files are opened my application opens.
Now when I do not change the name (eg I leave it as INFOPATH.EXE) it works as expected, however if it is called anything other than that then I get the error.
Unfortunately I need my application to open first.
I tried the below and it's works fine. Let me know what you get with this. (Don't forget to change path to files)
class Program
{
static void Main(string[] args)
{
System.Diagnostics.Process prc = new System.Diagnostics.Process();
prc.StartInfo.Arguments = string.Join("", Constants.Arguments);
prc.StartInfo.FileName = Constants.PathToInfoPath;
prc.Start();
}
}
public class Constants
{
public static string PathToInfoPath = #"C:\Program Files (x86)\Microsoft Office\Office14\INFOPATH.EXE";
public static string[] Arguments = new string[] { #"c:\users\accountname\Desktop\HSE-000403.xml" };
}

Categories