string manipulation using Directory.GetFiles() - c#

i am assigning images[] with an array that holds images file names with full path of given Directory.
string[] images = DirLoad.FileNamesArray(
IO.Loaders.PathType.full,
IO.Loaders.FileExtension.jpg
);
...now, that images[] stores all the file names i need, as I had to use the full path to get it done,
using Directory.GetFiles()
Next action requires it as a local file name.
(each is then passed as string type parameter to another method)
so my question is :
How can i omit first part - HttpRuntime.AppDomainAppPath ...if it's same in every element of array ?
this is usage example, the string is currentDir i need to trim from each element in images[]
public class IO
{
public class Loaders
{
readonly string currentDir = HttpRuntime.AppDomainAppPath;
public string selecedDirName { get; set; }
/// <summary>
/// assign The Loaders.selectedDir First before calling
/// </summary>
/// <param name="foldertoLoad"></param>
/// <returns></returns>
public enum PathType
{
full, local
}
public enum FileExtension
{
jpg,png,txt,xml,htm,js,aspx,css
}
public string[] FileNamesArray(PathType SelectedPathMode, FileExtension selectedfileType)
{
string thisFolder = "";
string thatFileType= string.Format("*.{0}",selectedfileType.ToString());
switch (SelectedPathMode)
{
case PathType.full:
thisFolder = Path.Combine(currentDir, selecedDirName);
break;
case PathType.local:
thisFolder = selecedDirName;
break;
default:
break;
}
string[] foundArr = Directory.GetFiles(thisFolder, thatFileType);
return foundArr;
}
}
}
Update , this is what i've tried
string fileName;
string[] images = DirLoad.FilesArray(IO.Loaders.PathType.full, IO.Loaders.FileExtention.jpg);
foreach (var currImage in images)
{
int startingAt = DirLoad.currentDir.Length ;
int finalPoint = currImage.Length - startingAt;
fileName = new String(currImage.ToCharArray(startingAt, finalPoint));
baseStyle.Add(string.Format("{0}url({1}) {2}", BackGroundCssProp, fileName, imageProps));
}
return baseStyle.ToArray();

Still I fail to understand, what you're trying to accomplish from the beginning to the end, but..If you are having an array of full paths and you need to get only filenames from these paths, you can do the following:
Actually files may contain random, absolutely different paths, but according to what I have caught from the question, et it be:
var files = Directory.GetFiles(#"path");
Then you may use Path.GetFileName Method to retrieve only filename from these paths, through a simple Enumerable.Select LINQ-statement:
var fileNamesOnly = files.Select(f => Path.GetFileName(f));

I am not entirely sure what you exactly need. For your sentence:
the string is currentDir i need to trim from each element in images[]
You can try the following using LINQ:
string currDir = "SomeString";
string[] images = new string[] { "SomeStringabc1.jpg", "SomeStringabc2.jpg", "SomeStringabc3.jpg", "abc.jpg" };
string[] newImages = images.Select(r => r.StartsWith(currDir)
? r.Replace(currDir, "") : r)
.ToArray();
Or using string.TrimStart
string[] newImages = images.Select(r => r.TrimStart(currDir.ToCharArray())).ToArray();

sorry but it is not clear to me... if you want only the filename from whole path then you can simply use Split for it, split the whole path with special character and use last array element.
once you will get all the path in your "images" array you can try below code.
for example:-
for(i=0;i<images.length;i++)
{
string [] cuttofilename=images[i].split('\');
string filename=cuttofilename[cuttofilename.lentgh-1];
}

Related

Converting from vb.net to c#, switch function not working

So I have been working on a small project (Previously built with vb.net) in C# ( Being honest, I have used an online vb.net to c# converter to get to this point.) that will basically rename the suffix of a set of files to specific predetermined names (hard coded).
Firstly the working part...
Press button_1, a file dialogue opens and you select files. These are then populated into a listbox_1.
Now press button_2 and the files from listbox_1 are renamed and sent to listbox_2.
Now the issue I am having...
For some reason I cannot figure out, the names are not being changed through the switch statement, they are just taking the string variable name and populating listbox_2 with blank entries (Because the starting Variable is empty).
string NewFileName = "";
I'm not sure what is happening here at all so if anyone is able to help me out that would be great.
private string GetNewName(string OriginalFileName)
{
string NewFileName = "";
switch (true)
{
case object _ when OriginalFileName.Contains(".0001"):
{
NewFileName = OriginalFileName.Replace(".0001", "APPLE");
break;
}
case object _ when OriginalFileName.Contains(".0002"):
{
NewFileName = OriginalFileName.Replace(".0002", "PEAR");
break;
}
}
return NewFileName;
}
private void BTN_ProcessNames_Click(object sender, EventArgs e)
{
foreach (Tuple<string, string> t in listbox_1.Items)
{
var NewName = GetNewName(t.Item2);
listbox_2.Items.Add(NewName);
}
}
I would create a mapping:
private static readonly IReadOnlyDictionary<string, string> _mapping = new Dictionary<string, string>()
{
{ "0001", "APPLE" },
{ "0002", "PEAR" }
};
And then a method to extract the id, look it up in the mapping, and replace it:
private string GetNewName(string originalFileName)
{
// if the path is c:\test\Green_.0001.jpg then we'll end up with filePath containing c:\test and fileName containing Green_.0001.jpg
string filePath = Path.GetDirectoryName(originalFileName);
string fileName = Path.GetFileName(originalFileName); // get only the name part
// Split the filename by .
string[] parts = fileName.Split('.');
// If we have enough parts in the filename try and extract the id and replace it
if (parts.Length >= 2)
{
// extract the id (e.g. 0001)
string id = parts[parts.Length - 2];
// look it up in the mapping dictionary
if (_mapping.TryGetValue(id, out var newName))
{
// join everything up to the id (i.e. Green_)
string leftPart = string.Join(".", parts.Take(parts.Length - 2));
// Append the new name and the last part (the extension)
fileName = $"{leftPart}{newName}.{parts.Last()}";
}
}
// Recombine the filePath and fileName
return Path.Combine(filePath, fileName);
}
Note that this method will return the original filename if the id isn't in the mapping, or the filename doesn't contain enough .s.
Try it online
Use if else statement. If you want to use switch then check at first and then use the switch.
Use below link for reference.
Use string.Contains() with switch()

How can i fill a list or array when checking in condition?

begginer here :). So i want to fill an array or list with results from a foreach loop.
Noob example
foreach (var drive in mounted_drives)
{
//asigning new path where to look for the UNCpath
string getUNC = path + "\\" + drive;
reg2 = Registry.CurrentUser.OpenSubKey(getUNC);
string UNCPath = reg2.GetValue("RemotePath").ToString(); //getting UNC PATH
Console.WriteLine(UNCPath);
}
so here i want each UNCPath to be saved to outside array or list that i can use later to write it in a file.
Dont wanna spill here my ideas since im not that deep into C# and .NET yet..
It may be simple but im stuck -.-
Thanks in advance
You can try this:
List<string> mylist = new List<string>();
foreach (var drive in mounted_drives)
{
string getUNC = path + "\\" + drive;
reg2 = Registry.CurrentUser.OpenSubKey(getUNC);
string UNCPath = reg2.GetValue("RemotePath").ToString(); //getting UNC PATH
mylist.Add(UNCPath);
}
In case you should need to have an array instead of a list, you can use the method ToArray();
string[] myarray = mylist.ToArray();
So i want to fill an array or list with results from a foreach loop. I want each UNCPath to be saved to outside array or list that I can use later.
There are other answer that address this already, but I have a different approach to this and a few suggestions to improve your current code.
The first suggestion is don't concatenate strings like you are:
string getUNC = path + "\\" + drive;
Look into the Path.Combine Method to do this for you.
Secondly you should always release resources when you can. You are opening up registry keys which means we should also always close and dispose of them.
Below is a static class with an extension routine. The routine returns an IEnumerable<string>, this way it can defer execution until you actually need it. This is helpful considering you mentioned you want to use it later as a List<string> and or Array.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Win32;
public static class RegistryHelper
{
public static IEnumerable<string> GetRemotePaths(this IEnumerable<string> drives, string path)
{
if (drives == null || drives.Count() == 0 || string.IsNullOrEmpty(path))
yield break;
foreach (string drive in drives)
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(Path.Combine(path, drive)))
{
if (key != null && key.GetValue("RemotePath") != null)
{
yield return key.GetValue("RemotePath").ToString();
key.Close();
}
}
}
}
}
Here's an example of usage for this extension routine:
var ienum = mounted_drives.GetRemotePaths(YOURPATHHERE); // Make sure to put your path in - delayed execution until you actually need it
var lstPaths = mounted_drives.GetRemotePaths(YOURPATHHERE).ToList(); // Make sure to put your path in - converts the return to a `List<string>`
var arrPaths = mounted_drives.GetRemotePaths(YOURPATHHERE).ToArray(); // Make sure to put your path in - converts the return to an array of strings
You can just create a List outside the foreach and then appending what you want inside it.
var list = new List<string>();
list.Add("my string");
You can also use the Select method:
var list = mounted_drives.Select(e => {
string getUNC = path + "\\" + drive;
reg2 = Registry.CurrentUser.OpenSubKey(getUNC);
string UNCPath = reg2.GetValue("RemotePath").ToString(); //getting UNC PATH
return UNCPath;
}).ToList();

Remove parts of string

I have the following string
string a = #"\\server\MainDirectory\SubDirectoryA\SubdirectoryB\SubdirectoryC\Test.jpg";
I'm trying to remove part of the string so in the end I want to be left with
string a = #"\\server\MainDirectory\SubDirectoryA\SubdirectoryB";
So currently I'm doing
string b = a.Remove(a.LastIndexOf('\\'));
string c = b.Remove(b.LastIndexOf('\\'));
Console.WriteLine(c);
which gives me the correct result. I was wondering if there is a better way of doing this? because I'm having to do this in a fair few places.
Note: the SubdirectoryC length will be unknown. As it is made of the numbers/letters a user inputs
There is Path.GetDirectoryName
string a = #"\\server\MainDirectory\SubDirectoryA\SubdirectoryB\SubdirectoryC\Test.jpg";
string b = Path.GetDirectoryName(Path.GetDirectoryName(a));
As explained in MSDN it works also if you pass a directory
....passing the returned path back into the GetDirectoryName method will
result in the truncation of one folder level per subsequent call on
the result string
Of course this is safe if you have at least two directories level
Heyho,
if you just want to get rid of the last part.
You can use :
var parentDirectory = Directory.GetParent(Path.GetDirectoryName(path));
https://msdn.microsoft.com/de-de/library/system.io.directory.getparent(v=vs.110).aspx
An alternative answer using Linq:
var b = string.Join("\\", a.Split(new string[] { "\\" }, StringSplitOptions.None)
.Reverse().Skip(2).Reverse());
Some alternatives
string a = #"\\server\MainDirectory\SubDirectoryA\SubdirectoryB\SubdirectoryC\Test.jpg";
var b = Path.GetFullPath(a + #"\..\..");
var c = a.Remove(a.LastIndexOf('\\', a.LastIndexOf('\\') - 1));
but I do find this kind of string extensions generally usefull:
static string beforeLast(this string str, string delimiter)
{
int i = str.LastIndexOf(delimiter);
if (i < 0) return str;
return str.Remove(i);
}
For such repeated tasks, a good solution is often to write an extension method, e.g.
public static class Extensions
{
public static string ChopPath(this string path)
{
// chopping code here
}
}
Which you then can use anywhere you need it:
var chopped = a.ChopPath();

How combine two different Paths

I have two different Paths:
C:\Project\v4.0\Tool\Custom\CustomCompanyNames\Template\file\file.xml
C:\Destination\New\Place\Bin\Debug\output
I need a way two get values from two different paths
Expected Path:
C:\Destination\New\Place\Bin\Debug\output\CustomCompanyNames\file\file.xml
How can i solve it ?
Custom is a fix folder
All directories after Customs have different names
My Solution bad programmed:
Custom ist the first path
Destination the second path
private void test()
{
string result = destination;
string[] custom = customs.Split('\\');
foreach (var s in custom)
{
if(s.Contains("custom") || result.Contains("custom"))
{
if(s.Contains("templates")) break;
result = Path.Combine(result, s);
}
}
}
Instead of Splitting the path use IndexOf to find the Custom part and then Substring from it.
string path1 = #"C:\Project\v4.0\Tool\Custom\CustomCompanyNames\Template\file\file.xml";
string path2 = #"C:\Destination\New\Place\Bin\Debug\output";
string splitter = #"Custom\";
string desiredSection = path1.Substring(path1.IndexOf(splitter) + splitter.Length);
string output = Path.Combine(path2, desiredSection);

How to check for a part of the string in the file?

I am trying to write a code that will check all files under given directory and sub directories for a string passed from the web page. As of now I have this code:
private void ProcessDirectory(string targetDirectory, string origDirectory, string ObjectName)
{
string[] fileEntries = Directory.GetFiles(targetDirectory);
string[] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach (string fileName in fileEntries)
{
ProcessFile(fileName, origDirectory, ObjectName);
}
foreach (string subdirectory in subdirectoryEntries)
ProcessDirectory(subdirectory, origDirectory, ObjectName);
}
private void ProcessFile(string path, string origDirectory, string ObjectName)
{
if (ObjectName != "")
{
var fileLines = File.ReadAllLines(path);
List<string> fileItems = new List<string>(fileLines);
if (fileItems.Contains(ObjectName))
{
string sExt = Path.GetExtension(path).ToLower();
if (sExt == ".txt")
{
listTextFiles.Items.Add(path.Replace(origDirectory, ""));
}
}
}
It works, but the problem is that it looks only for a complete word in the file. For example, if I look for the word 'Account', and the file contains word 'Account', my code will work. If the file contains the word 'AccountCode', my search won't find it. Is there a way to fix it?
Another question, how to add a counter that would show at the end of the process how many files were checked under the given directory and all sub directories.
This is an awfully round-about way of doing it. Just load the entire file content and use IndexOf:
var content = File.ReadAllText(path);
if (content.IndexOf(ObjectName) > -1) {
// rest of your code here
}
There is no need to load line-by-line, initialize a whole new list with those lines, and check each line.
This also gives the benefit of a partial search, as you've asked.
You could probably improve this immensely by carefully auditing how much memory you're consuming. Both your method and the one I provided here will likely allocate large blocks of memory, only for them to be useless after the conditional check. Consider using a StringBuilder and re-using it with each file.
if fileItems.Contains(ObjectName)) will search the list fileItems on the condition: if that list contains items that is equal to ObjectName.
You probably want: if that list contains items that contains ObjectName. So change to this:
if (fileItems.Any(e => e.Contains(ObjectName)))
To answer the second question. Because you use recursion here you would need to declare a property or class level variable and increment it in your ProcessFile method e.g.:
public int NumberOfMatches { get; set; }
ProcessFile...
{
if (fileItems.Contains(ObjectName))
{
NumberOfMatches++;
}
As a side note there is no reason to use recursion here you could simply get all the files with a single call:
string[] allFiles = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
You may also consider mutli-threading if performance is an issue:
Parallel.ForEach(allFiles,
new ParallelOptions { MaxDegreeOfParallelism = 4 },
allFiles =>
{
...
}
When checking contents of a string, don't forget to implement a comparer for the string
If(string.Contains( value ,StringComparer.CurrentCultureIgnoreCase ))
// Apply logic...
It's very often left out...

Categories

Resources