Overview
I'm in the process of porting a simple utility app over from C# into Java and as part of this I'm writing some helper methods for items where I prefer C#'s semantics. Once such case is Directory.GetFiles.
Current Code
import java.io.File;
import java.io.FilenameFilter;
public class Directory {
public static String[] GetFiles(String path) {
File directory = new File(path);
return directory.list(new FilenameFilter() {
#Override
public boolean accept(File dir, String filename) {
return new File(dir, filename).isFile();
}
});
}
}
Question
Whilst the above all seems fine, and replicates one of the GetFiles overloads, I'm stuck on how best to write a method that replicates the functionality of C#'s Directory.GetFiles(String, String).
This method should take a path string, as well as a searchPattern, which is used to return only files matching that particular pattern.
For example, each of the following should work:
// Used to get all JavaScript files
Directory.GetFiles("~/Documents/", "*.js");
// Get all CSS files in the styles sub-folder.
Directory.GetFiles("~/Documents/", "styles/*.css");
You could modify the pattern by placing a period before each asterisk and question mark, and then use this as a regular expression to determine which files you should return. So, you could write something like
public static String[] GetFiles(final String path, final String searchPattern) {
final Pattern re = Pattern.compile(searchPattern.replace("*", ".*").replace("?", ".?"));
return new File(path).list(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return new File(dir, name).isFile() && re.matcher(name).matches();
}
});
}
Using Adam Michalcin's answer as a base, I've come up with the following (note these methods return an array of absolute paths:
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Pattern;
public class Directory {
public static String[] GetFiles(String path) {
File directory = new File(path);
File[] matchingFiles = directory.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String filename) {
return new File(dir, filename).isFile();
}
});
ArrayList<String> files = new ArrayList<String>();
for (File file : matchingFiles) {
files.add(file.getAbsolutePath());
}
return (String[])files.toArray(new String[files.size()]);
}
public static String[] GetFiles(String path, final String searchPattern) {
// Split the searchPattern incase we have directories in there
ArrayList<String> pattern = new ArrayList<String>(Arrays.asList(searchPattern.split("/")));
// Take the last element out from the array, as this will be the file pattern
String filePattern = pattern.remove(pattern.size() - 1);
// Insert the base path into the remaining list
pattern.add(0, path);
// Now lets concat the lot to create a base path
path = Path.combine((String[])pattern.toArray(new String[pattern.size()]));
final Pattern regEx = Pattern.compile(filePattern.replace("*", ".*").replace("?", ".?"));
File directory = new File(path);
File[] matchingFiles = directory.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String filename) {
return new File(dir, filename).isFile() && regEx.matcher(filename).matches();
}
});
ArrayList<String> files = new ArrayList<String>();
for (File file : matchingFiles) {
files.add(file.getAbsolutePath());
}
return (String[])files.toArray(new String[files.size()]);
}
}
This also utilizes another helper I've put in place (Path.combine):
import java.io.File;
public class Path {
public static String combine(String... paths)
{
File file = new File(paths[0]);
for (int i = 1; i < paths.length ; i++) {
file = new File(file, paths[i]);
}
return file.getPath();
}
}
Usage
Directory.GetFiles("/Users/beardtwizzle/", "/Documents/javascripts/*.js");
This does still the other character problem that Bruno Silva mentions. So will try and bake a fix in for that too.
Related
Is it possible to get only list of Excel filenames (like : 2021070701.CSV) in a folder ?
I'm getting the full path of the .csv excel when I use this "Directory.GetFiles" but I want to filter only excel filename with extension (like : 2021070701.CSV)
I used "FileInfo fi = new FileInfo();" but I didn't get the proper solution.
public static void getExcelFileName()
{
string[] filename = Directory.GetFiles(#"C:\Users\Ashok
Kumar\OneDrive\Desktop\Ashok\MarketPrice\NSE\Futures\Live", "*.csv");
foreach (var item in filename)
{
Console.WriteLine(item);
}
}
This is the path I'm getting
Help me out form this I'm new to coding.
You can use the GetFileNameWithoutExtension() method from the Path class to get the names of your files.
public static void getExcelFileName()
{
string[] filename = Directory.GetFiles(#"C:\Users\Ashok
Kumar\OneDrive\Desktop\Ashok\MarketPrice\NSE\Futures\Live", "*.csv");
foreach (var item in filename)
{
Console.WriteLine(Path.GetFileNameWithoutExtension(item));
}
}
Sure, you can call Path.GetFileName(string) which returns exactly what you're asking for!
public static void getExcelFileName()
{
string[] filesPaths = Directory.GetFiles(#"C:\Users\Ashok Kumar\OneDrive\Desktop\Ashok\MarketPrice\NSE\Futures\Live",
"*.csv");
foreach (var filePath in filesPaths)
{
Console.WriteLine(Path.GetFileName(filePath));
}
}
I'm working with some dynamic bundling which adds CSS and JS files based on configuration.
I spin up a new StyleBundle such that:
var cssBundle = new StyleBundle("~/bundle/css");
Then loop through config and add any found includes:
cssBundle.Include(config.Source);
Following the loop I want to check if there was actually any files/directories included. I know there's EnumerateFiles() but I don't think this 100% serves the purpose.
Anyone else done anything similar previously?
The Bundle class uses an internal items list that is not exposed to the application, and isn't necessarily accessible via reflection (I tried and couldn't get any contents). You can fetch some information about this using the BundleResolver class like so:
var cssBundle = new StyleBundle("~/bundle/css");
cssBundle.Include(config.Source);
// if your bundle is already in BundleTable.Bundles list, use that. Otherwise...
var collection = new BundleCollection();
collection.Add(cssBundle)
// get bundle contents
var resolver = new BundleResolver(collection);
List<string> cont = resolver.GetBundleContents("~/bundle/css").ToList();
If you just need a count then:
int count = resolver.GetBundleContents("~/bundle/css").Count();
Edit: using reflection
Apparently I did something wrong with my reflection test before.
This actually works:
using System.Reflection;
using System.Web.Optimization;
...
int count = ((ItemRegistry)typeof(Bundle).GetProperty("Items", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(cssBundle, null)).Count;
You should probably add some safety checks there of course, and like a lot of reflection examples this violates the intended safety of the Items property, but it does work.
You can use the following extension methods for Bundle:
public static class BundleHelper
{
private static Dictionary<Bundle, List<string>> bundleIncludes = new Dictionary<Bundle, List<string>>();
private static Dictionary<Bundle, List<string>> bundleFiles = new Dictionary<Bundle, List<string>>();
private static void EnumerateFiles(Bundle bundle, string virtualPath)
{
if (bundleIncludes.ContainsKey(bundle))
bundleIncludes[bundle].Add(virtualPath);
else
bundleIncludes.Add(bundle, new List<string> { virtualPath });
int i = virtualPath.LastIndexOf('/');
string path = HostingEnvironment.MapPath(virtualPath.Substring(0, i));
if (Directory.Exists(path))
{
string fileName = virtualPath.Substring(i + 1);
IEnumerable<string> fileList;
if (fileName.Contains("{version}"))
{
var re = new Regex(fileName.Replace(".", #"\.").Replace("{version}", #"(\d+(?:\.\d+){1,3})"));
fileName = fileName.Replace("{version}", "*");
fileList = Directory.EnumerateFiles(path, fileName).Where(file => re.IsMatch(file));
}
else // fileName may contain '*'
fileList = Directory.EnumerateFiles(path, fileName);
if (bundleFiles.ContainsKey(bundle))
bundleFiles[bundle].AddRange(fileList);
else
bundleFiles.Add(bundle, fileList.ToList());
}
}
public static Bundle Add(this Bundle bundle, params string[] virtualPaths)
{
foreach (string virtualPath in virtualPaths)
EnumerateFiles(bundle, virtualPath);
return bundle.Include(virtualPaths);
}
public static Bundle Add(this Bundle bundle, string virtualPath, params IItemTransform[] transforms)
{
EnumerateFiles(bundle, virtualPath);
return bundle.Include(virtualPath, transforms);
}
public static IEnumerable<string> EnumerateIncludes(this Bundle bundle)
{
return bundleIncludes[bundle];
}
public static IEnumerable<string> EnumerateFiles(this Bundle bundle)
{
return bundleFiles[bundle];
}
}
Then simply replace your Include() calls with Add():
var bundle = new ScriptBundle("~/test")
.Add("~/Scripts/jquery/jquery-{version}.js")
.Add("~/Scripts/lib*")
.Add("~/Scripts/model.js")
);
var includes = bundle.EnumerateIncludes();
var files = bundle.EnumerateFiles();
If you are also using IncludeDirectory(), just complete the example by adding a respective AddDirectory() extension method.
On my FTP Server I have the following folder structure
- Parent Directory
-a.txt
-b.txt.old
-SubDirectory1
-c.txt
-NestedSubDirectory1
-d.txt
-SubDirectory2
-e.txt
-f.txt.old
The number of SDs are not fixed. I need a way to get all the files(can be any format) without the .old extension from the Parent Directory.
I'm currently using the 3rd party dll edtFTPnet.
ftpConnection.GetFileInfos()Where(f => !(f.Name.EndsWith(".old"))).ToList();
This helps me get the details of the files and folders at the current working directory level.
Can someone tell me a way to get all the files with the parentdirectory, subdirectories and nested subdirectories.
The solution may or may not use edtFTPnet.
FTPConnection.GetFileInfos() returns an array of FTPFile. The class FTPFile has a boolean property Dir which indicates whether its filename accesses a file (false) or directory (true).
Something like this should work:
void ReadSubDirectories(FTPConncetion connection, FTPFile[] files)
{
foreach (var file in files)
{
if (file.Dir)
{
// Save parent directory
var curDir = connection.ServerDirectory;
// Move into directory
connection.ChangeWorkingDirectory(file.Name)
// Read all files
ReadSubDirectories(connection, connection.GetFileInfos());
// Move back into parent directory
connection.ChangeWorkingDirectory(curDir)
}
else
{
// Do magic with your files
}
}
}
However you might be better off using just .NET's built-in FtpWebRequest class since its methods and naming conventions are clearer, it's better documented and it's easier to find references online.
Try to use extensions like this:
class Program
{
static void Main(string[] args)
{
using (var connection = new FTPConnection
{
ServerAddress = "127.0.0.1",
UserName = "Admin",
Password = "1",
})
{
connection.Connect();
connection.ServerDirectory = "/recursive_folder";
var resultRecursive =
connection.GetFileInfosRecursive().Where(f => !(f.Name.EndsWith(".old"))).ToList();
var resultDefault = connection.GetFileInfos().Where(f => !(f.Name.EndsWith(".old"))).ToList();
}
}
}
public static class FtpClientExtensions
{
public static FTPFile[] GetFileInfosRecursive(this FTPConnection connection)
{
var resultList = new List<FTPFile>();
var fileInfos = connection.GetFileInfos();
resultList.AddRange(fileInfos);
foreach (var fileInfo in fileInfos)
{
if (fileInfo.Dir)
{
connection.ServerDirectory = fileInfo.Path;
resultList.AddRange(connection.GetFileInfosRecursive());
}
}
return resultList.ToArray();
}
}
how to access a text file based on its prefix
var str = GrvGeneral.Properties.Resources.ResourceManager.GetString(configFile + "_Nlog_Config");
var str1 = GrvGeneral.Properties.Resources.ResourceManager.GetObject(configFile + "_Nlog_Config");
where the configfile is the prefix of the resourcefile A & B .
Based on the configfile contents (prefix) the resource file A & B has to be accessed .
Use the DirectoryInfo class (documentation). Then you can call the GetFiles with a search pattern.
string searchPattern = "abc*.*"; // This would be for you to construct your prefix
DirectoryInfo di = new DirectoryInfo(#"C:\Path\To\Your\Dir");
FileInfo[] files = di.GetFiles(searchPattern);
Edit: If you have a way of constructing the actual file name you're looking for, you can go directly to the FileInfo class, otherwise you'll have to iterate through the matching files in my previous example.
Your question is rather vague...but it sounds like you want to get the text contents of an embedded resource. Usually you would do that using Assembly.GetManifestResourceStream. You can always use LINQ along with Assembly.GetManifestResourceNames() to find the name of an embedded file matching a pattern.
The ResourceManager class is more often used for automatically retrieving localized string resources, such as labels and error messages in different languages.
update: A more generalized example:
internal static class RsrcUtil {
private static Assembly _thisAssembly;
private static Assembly thisAssembly {
get {
if (_thisAssembly == null) { _thisAssembly = typeof(RsrcUtil).Assembly; }
return _thisAssembly;
}
}
internal static string GetNlogConfig(string prefix) {
return GetResourceText(#"Some\Folder\" + prefix + ".nlog.config");
}
internal static string FindResource(string pattern) {
return thisAssembly.GetManifestResourceNames()
.FirstOrDefault(x => Regex.IsMatch(x, pattern));
}
internal static string GetResourceText(string resourceName) {
string result = string.Empty;
if (thisAssembly.GetManifestResourceInfo(resourceName) != null) {
using (Stream stream = thisAssembly.GetManifestResourceStream(resourceName)) {
result = new StreamReader(stream).ReadToEnd();
}
}
return result;
}
}
Using the example:
string aconfig = RsrcUtil.GetNlogConfig("a");
string bconfigname = RsrcUtil.FindResource(#"b\.\w+\.config$");
string bconfig = RsrcUtil.GetResourceText(bconfigname);
I have to get the path excluding the relative path from the full path,
say
The relative path is ,C:\User\Documents\
fullpath ,C:\User\Documents\Test\Folder2\test.pdf
I want to get only the path after the relative path i.e \Test\Folder2\test.pdf
how can i achieve this.
I am using C# as the programming language
You are not talking about relative, so i will call it partial path.
If you can be sure that the partial path is part of your full path its a simple string manipulation:
string fullPath = #"C:\User\Documents\Test\Folder2\test.pdf";
string partialPath = #"C:\User\Documents\";
string resultingPath = fullPath.Substring(partialPath.Length);
This needs some error checking though - it will fail when either fullPath or partialPath is null or both paths have the same length.
Hmmmm, but what if the case is different? Or one of the path uses short-names for its folders? The more complete solution would be...
public static string GetRelativePath(string fullPath, string containingFolder,
bool mustBeInContainingFolder = false)
{
var file = new Uri(fullPath);
if (containingFolder[containingFolder.Length - 1] != Path.DirectorySeparatorChar)
containingFolder += Path.DirectorySeparatorChar;
var folder = new Uri(containingFolder); // Must end in a slash to indicate folder
var relativePath =
Uri.UnescapeDataString(
folder.MakeRelativeUri(file)
.ToString()
.Replace('/', Path.DirectorySeparatorChar)
);
if (mustBeInContainingFolder && relativePath.IndexOf("..") == 0)
return null;
return relativePath;
}
To expand on Jan's answer, you could create an extension method on the string class (or the Path class if you wanted) such as:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static string GetPartialPath(this string fullPath, string partialPath)
{
return fullPath.Substring(partialPath.Length)
}
}
}
And then use:
using ExtensionMethods;
string resultingPath = string.GetPartialPath(partialPath);
I haven't tested that this extension method works, but it should do.