I am using:
File.Exists(filepath)
What I would like to do is swop this out for a pattern, because the first part of the filename changes.
For example: the file could be
01_peach.xml
02_peach.xml
03_peach.xml
How can I check if the file exists based on some kind of search pattern?
You can do a directory list with a pattern to check for files
string[] files = System.IO.Directory.GetFiles(path, "*_peach.xml", System.IO.SearchOption.TopDirectoryOnly);
if (files.Length > 0)
{
//file exist
}
If you're using .net framework 4 or above you could use Directory.EnumerateFiles
bool exist = Directory.EnumerateFiles(path, "*_peach.xml").Any();
This could be more efficient than using Directory.GetFiles since you avoid iterating trough the entire file list.
Get a list of all matching files using System.IO.DirectoryInfo.GetFiles()
Also see SO Questions:
Is there a wildcard expansion option for .net apps?
How do I check if a filename matches a wildcard pattern
and many others...
For more advanced searching against a specific pattern, it might be worth using File Globbing which allows you to use search patterns like you would in a .gitignore file.
See here: https://learn.microsoft.com/en-us/dotnet/core/extensions/file-globbing
This allows you to add both inclusions & exclusions to your search.
Please see below the example code snippet from the Microsoft Source above:
Matcher matcher = new Matcher();
matcher.AddIncludePatterns(new[] { "*_peach.xml" });
IEnumerable<string> matchingFiles = matcher.GetResultsInFullPath(filepath);
Related
I've a directory with tons of files and I want only to get the names of the ones starting with sly_.
If I'm not wrong, the patter for this is ^sly_.
This is my try using the solution of this question:
string pattern = #"^sly_";
var matches = Directory.GetFiles(#"D:\mypath").Where(path => Regex.Match(path, pattern).Success);
foreach (string file in matches)
Console.Write(file);
Unfortunatelly, this doesn't list the files matching my pattern. So, can someone tell me what's wrong with me code and how can I list the file names starting with sly_?
Thanks in advance.
If you insist on regular expression you should test FileName, not the entire path:
string pattern = #"^sly_";
var matches = Directory
.GetFiles(#"D:\mypath")
.Where(path => Regex.IsMatch(Path.GetFileName(path), pattern));
Console.Write(String.Join(Environment.NewLine, matches));
Your actual issue is that Directory.GetFiles returns
An array of the full names (including paths) for the files in the specified directory, or an empty array if no files are found.
You regex would need to check for the D:\mypath part as well as the sly_ part. Other than that, your expression is correct.
You don't need to use regex at all. This is more readable and efficient:
string[] matches = Directory.GetFiles(#"D:\mypath", "sly_*");
Directory.GetFiles Method (String, String)
* is a wildcard for "zero or more characters in that position" and it's used only one the file-name not the full-path. If you wanted to include the extension:
string[] matches = Directory.GetFiles(#"D:\mypath", "sly_*.txt");
Your regex would also work if you just use the file-name not the full-path:
var matches = Directory.GetFiles(#"D:\mypath")
.Where(path => Regex.Match(Path.GetFileName(path), pattern).Success);
But as mentioned, this is less readable and not efficient. Remember that matches currently is only a LINQ query, not a collection. You need to add f.e. ToArray to get one. Otherwise this query is executed always when you use matches.
This is easy using Linq and classes DirectoryInfo and FileInfo. A FileInfo has properties FileName and FullFileName. Usage would be as follows:
IEnumerable<FileInfo> myFiles = new DirectoryInfo(#"D:\mypath")
.EnumerateFiles()
.Where(fileInfo => fileInfo.Name.StartsWith("sly_", StringComparison.OrdinalIgnoreCase));
Use Enumerable.Select to get the sequence with full file names or short file names
Why your code is not working is, Directory.GetFiles() returns the full path of files, like
D:\mypath\sly_yourFile.txt
So, the string path doesn't start with sly_ and does not match your Regex #"^sly_".
A simpler solution is to provide the search pattern to GetFiles() method like
Directory.GetFiles(#"D:\mypath", "sly_*")
I am attempting to retrieve jpeg and jpg files using the following statement:
string[] files = Directory.GetFiles(someDirectoryPath, "*.jp?g");
MSDN's docs for System.IO.Directory.GetFiles(string, string) state that ? represents "Exactly zero or one character.", however the above block selects jpeg files but omits jpg files.
I am currently using the overly-permissive search pattern "*.jp*g" to achieve my results, but it wrinkles my brain because it should work.
From the docs you linked to:
A searchPattern with a file extension of one, two, or more than three characters returns only files having extensions of exactly that length that match the file extension specified in the searchPattern.
I suspect that's the problem. To be honest, I'd probably fetch all the files and then postprocess them in code - it'll make for code which is simpler to reason about than relying on the Windows path-handling oddities.
You could either use "*" as a pattern and process the result yourself OR use
string[] files = Directory.GetFiles(someDirectoryPath, "*.jpg").Union (Directory.GetFiles(someDirectoryPath, "*.jpeg")).ToArray();
According to the Docs the pattern you use would return only files with extensions which are 4 characters long.
MSDN reference on Union
I know how to get all files that match the search pattern in a folder like this:
DirectoryInfo folderInfo = new DirectoryInfo(folderPath);
FileInfo[] fileInfos = folderInfo.GetFiles(searchPattern);
But my problem is, if I already know the file path, how can I match it with the search pattern? For compatibility, the search pattern has to be the same format like *.jpg or something.
I'm interpreting your question as meaning you already have a string for the file path and just want to check whether it matches a certain pattern. For this you first need to consider whether pattern patching is really what you need, it may be preferable to just use the extension directly for example.
Assuming that is not an option, you're probably going to want to use regular expressions. You will need to convert the string with wild-cards to a regular expression. Unfortunately I'm not aware of any built in ways of doing this, but it should be possible to do by simply escaping any characters which would have meaning in a regex and replacing the wild cards with appropriate regular expressions.
Well if you already have the full file path and you isolate the extension only, using Path.GetExtension or similar, then you just add a * before you are are set, right?
If u already know the path, Don't use search pattern.
Try
FileInfo fi = new FileInfo(FilePath);
you can use Directory.GetFiles like "Directory.GetFiles("d:/xxx/*.jpg")" to get string array of all match files, and then to open or handle the single file.
The directory 'C:\temp' has two files named 'GZ96A7005.tif' and 'GZ96A7005001.tif'. They have different length with the same extension. Now I run below code:
string[] resultFileNames = Directory.GetFiles(#"C:\temp", "????????????.tif");
The 'resultFileNames' return two items 'c:\temp\GZ96A7005.tif' and 'c:\temp\GZ96A7005001.tif'.
But the Window Search will work fine. This is why and how do I get I want?
For Directory.GetFiles, ? signifies "Exactly zero or one character." On the other hand, you could use DirectoryInfo.GetFiles, for which ? signifies "Exactly one character" (apparently what you want).
EDIT:
Full code:
string[] resultFileNames = (from fileInfo in new DirectoryInfo(#"C:\temp").GetFiles("????????????.tif") select fileInfo.Name).ToArray();
You can probably skip the ToArray and just let resultFileNames be an IEnumerable<string>.
People are reporting this doesn't work for them on MS .NET. The below exact code works for me with on Mono on Ubuntu Hardy. I agree it doesn't really make sense to have two related classes use different conventions. However, that is what the documentation (linked above) says, and Mono complies with the docs. If Microsoft's implementation doesn't, they have a bug:
using System;
using System.IO;
using System.Linq;
public class GetFiles
{
public static void Main()
{
string[] resultFileNames = (from fileInfo in new DirectoryInfo(#".").GetFiles("????????????.tif") select fileInfo.Name).ToArray();
foreach(string fileName in resultFileNames)
{
Console.WriteLine(fileName);
}
}
}
I know I've read about this somewhere before, but the best I could find right now was this reference to it in Raymond Chen's blog post. The point is that Windows keeps a short (8.3) filename for every file with a long filename, for backward compatibility, and filename wildcards are matched against both the long and short filenames. You can see these short filenames by opening a command prompt and running "dir /x". Normally, getting a list of files which match ????????.tif (8) returns a list of file with 8 or less characters in their filename and a .tif extension. But every file with a long filename also has a short filename with 8.3 characters, so they all match this filter.
In your case both GZ96A7005.tif and GZ96A7005001.tif are long filenames, so they both have a 8.3 short filename which matches ????????.tif (anything with 8 or more ?'s).
UPDATE... from MSDN:
Because this method checks against
file names with both the 8.3 file name
format and the long file name format,
a search pattern similar to "*1*.txt"
may return unexpected file names. For
example, using a search pattern of
"*1*.txt" returns "longfilename.txt"
because the equivalent 8.3 file name
format is "LONGFI~1.TXT".
UPDATE: The MSDN docs specifiy different behavior for the "?" wildcard in Directory.GetFiles() and DirectoryInfo.GetFiles(). The documentation seems to be wrong, however. See Matthew Flaschen's answer.
The ? character matches "zero or one" characters... so from what you have I would imagine that your search pattern will match any file ending in ".tif" that is between zero and twelve characters long.
Try dropping another file in that is only three characters long with a ".tif" extension and see if the code picks that up as well. I have a sneaking suspicion that it will ;)
As far as the Windows search is concerned, it is most definately not using the same algorithm under the hood. The ? character might have a very different meaning there than it does in the .Net search pattern specification for the Directory.GetFiles(string, string) method.
string path = "C:/";
var files = Directory.GetFiles(path)
.Where(f => f.Replace(path, "").Length == 8);
A little costly with the string replacement. You can add whatever extension you need.
I've used the setargv.obj linking for Expanding Wildcard Arguments in the past for a number of C and C++ apps, but I can't find any similar mention for .net applications.
Is there a standard way to have your app's command line parameters automatically wildcard expanded? (i.e. expand *.doc from one entry in args parameter to all that match that wildcard).
P.S. I've hacked something together with Directory.GetFiles() for my current little project, but it does not cover wildcards with paths (yet), and it would be nice to do it without custom code.
Update: here is my rough hack, for illustration. It needs to split the parameters for the path and name for the GetFiles(), but this is a general idea. Linking setargv.obj into a C or C++ app would basically do all the wildcard expansion, leaving the user to only iterate over the argv array.
public static void Main(string[] args)
{
foreach (string argString in args)
{
// Split into path and wildcard
int lastBackslashPos = argString.LastIndexOf('\\') + 1;
path = argString.Substring(0, lastBackslashPos);
filenameOnly = argString.Substring(lastBackslashPos, argString.Length - lastBackslashPos);
string[] fileList = System.IO.Directory.GetFiles(path, filenameOnly);
foreach (string fileName in fileList)
{
// do things for each file
}
}
}
Here us my rough hack. I'd love for it to be recursive. And having experienced the shortcoming of Windows wildcards I might decide to use regular expressions rather than letting GetFiles() do it for me.
using System.IO;
public static string[] ExpandFilePaths(string[] args)
{
var fileList = new List<string>();
foreach (var arg in args)
{
var substitutedArg = System.Environment.ExpandEnvironmentVariables(arg);
var dirPart = Path.GetDirectoryName(substitutedArg);
if (dirPart.Length == 0)
dirPart = ".";
var filePart = Path.GetFileName(substitutedArg);
foreach (var filepath in Directory.GetFiles(dirPart, filePart))
fileList.Add(filepath);
}
return fileList.ToArray();
}
I'm not sure exactly what you're after... but if I get where you're going with the Directory.GetFiles() "hack" you mentioned, then something like this might work:
var Dirs = Directory.GetDirectories(#"C:\Windows", "sys*",
SearchOption.TopDirectoryOnly).ToList();
var Files = new List<String>();
Dirs.ForEach(dirName => Files.AddRange(Directory.GetFiles(dirName, "*.sys", SearchOption.AllDirectories)));
The wildcard option on the GetDirectories call will allow you to grab all the directories contained in the Windows folder [directly] that match the pattern "sys*".
You can then iterate over those folders grabbing all the files that match the pattern "*.sys".
Is that the kind of thing you're looking for? To automatically expand the args, you'd have to extract the wildcards in some kind of meaningful manner and apply them to that model...
For instance:
RunMyApp "C:\Windows\Sys*\ *.sys"
You'd pull out the string C:\Windows - probably with a regular expression, find the lowest level directory that doesn't contain a wildcard and apply it to the GetDirectories method, attaching the wildcarded string as the search parameter.
Then if your end of string (in this case *.sys) as the search pattern for Directory.GetFiles.
If you wanted to get more complicated and do something like:
C:\Windows\*\Sys*\*.sys
You would use the SearchOptions to set this behaviour:
Directory.GetDirectories(#"C:\Windows", "sys*", SearchOptions.AllDirectories)
This would grab all directories that matched the sys* wildcard in the Windows directory and all directories below it.
If you wanted to get much more complicated than that, then I'm not sure how you would do that... for instance, say you wanted folders that are contained by folders directly inside the Windows directory - I have no idea how you would go about something like that I'm afraid...I don't imagine exporting the entire tree structure to XML and using XPath to do it would be so efficient - the XPath would be fabulously simple for parsing out using wildcards - but converting to XML wouldn't be so efficient...
see the source code of disassembled Microsoft.Build.Shared.FileMatcher class in Microsoft.Build.dll
you can get some idea from the implementation of method GetFiles.
as a client you may use the method as follows
var filelist = FileMatcher.GetFiles(#"c:\alaki",#"c:\alaki\**\bin\*.dll");
Your code looks like exactly how you're supposed to do it.