The project on WinForms has a set of reports located in the folder and its subfolders, for example:

D:\Shared\Common\BaseReports\Main.rpt D:\Shared\Common\BaseReports\Main_new.rpt D:\Shared\Common\BaseReports\2015\Payments.rpt D:\Shared\Common\BaseReports\2016\Payments.rpt 

etc. The application itself can be located anywhere, and the path to the reports in it is indicated through the variable string reportPath = "D:\\Shared\\Common\\BaseReports";

In the future, let the path to a specific report be set using the base folder, for example, like this: string someReport = reportPath + "\\2015\\Payment.rpt";

How to get a list of folders and files inside D: \ Shared \ Common \ BaseReports \ in the form:

 Main.rpt Main_new.rpt 2015\Payments.rpt 2016\Payments.rpt 

...?

Yes, about string.Replace() [ string relativePath = someReport.Replace(reportPath, ""); ] I know, but maybe there is a better way? Thank!

  • ideone.com/vrQuf3 - but I'm not sure that this code will always work - Pavel Mayorov
  • @PavelMayorov: ideone.com/cLe7wf - VladD
  • @PavelMayorov, Thanks, on the English version of the portal, the recommendation is the same - BlackWitcher
  • @BlackWitcher that - thanks? It does not work) - Pavel Mayorov
  • @PavelMayorov works if in your code replace @"D:\Shared\Common\BaseReports"; on @"D:\Shared\Common\BaseReports\"; i.e. add a backslash at the end of the root path. - BlackWitcher

4 answers 4

Something like this.

 var baseDir = new DirectoryInfo("H:\\...\\Reports"); foreach(var file in baseDir.EnumerateFiles("*.rpt",SearchOption.AllDirectories)) { Console.WriteLine(file.FullName.Replace(baseDir.FullName + Path.DirectorySeparatorChar, string.Empty)); } 

Works with any depth of nested folders. There should be a minimum of read access for files and folders, otherwise there will be an exception, but if this is a user folder and the program can write reports with user rights there, then access problems should not be (diversion of the user does not count). Displays the correct system slashes in the paths. Works faster than using Directory.GetFiles()

  • Thank you for what you need. - BlackWitcher
  • use, as a bonus, FileInfo itself is able to open and return a file stream. - rdorn

As a modification of the answer, @rdorn is a small variation on the topic:

 public static IEnumerable<string> GetRelativeFolderContents (string folder, string searchPattern = "*") { //Проверки на валидность параметров if (!Directory.Exists(folder)) { //Нет пути для сканирования содержимого директории throw new IOException("Путь \"" + folder + "\" не существует."); } //Проверяем наличие разделителя папок в конце базового пути, и, если его нет - добавляем. if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString())) folder += Path.DirectorySeparatorChar; //Список для результата: List<string> result = new List<string>(); //Временная переменная: string t = ""; //Получаем содержимое базового пути, включая все вложенные папки и файлы: foreach (var item in Directory.EnumerateFileSystemEntries(folder, "*", SearchOption.AllDirectories)) { t = item.Replace(folder, string.Empty); //Проверяем, не ссылку ли на папку мы получили? if (Directory.Exists(item)) { //Папка пустая? if (!Directory.EnumerateFileSystemEntries(item).Any()) { //Если пустая - добавляем к результату (не пустые папки сами добавятся вместе с //путями к файлам, в них содержащимся) if (!item.EndsWith(Path.DirectorySeparatorChar.ToString())) { result.Add(t + Path.DirectorySeparatorChar); } else { result.Add(t); } } } else { result.Add(t); } } return result; } 

The main differences are minor, namely, additional checks and the use of Directory.EnumerateFileSystemEntries , and, as a result, empty folders will fall into the result of the sample if they exist and the search parameters allow it.

Will work in .NET 4.0 and higher.

  • one
    I advise you to add a forced cast of paths to the absolute (in case the user sets the wrong separator in the settings). - Pavel Mayorov
  • one
    Also, for reasons of defensive programming, file.StartsWith(root) should be checked, file.StartsWith(root) , throw an exception - Pavel Mayorov
  • one
    I corrected the answer below. It even works. - V. Dmitriy
  • @PavelMayorov, thanks, I agree. But "protection against a fool" as well as other exception handling deliberately left out of the brackets, so as not to clutter up once more. - BlackWitcher
  • 2
    @BlackWitcher in your project - please leave it behind the brackets. Because if an error occurs, you will fix it. But when you lay out the code for sharing - be prepared that someone who has less knowledge than you will use it. - Pavel Mayorov

If the application is planned to be used without VS. Then you can use "Getting the path to the directory of the executable file"

 new FileInfo(String.Concat(Assembly.GetExecutingAssembly().Location)).Directory.FullName 

and already search for files with the .rpt extension

And if the application will work only with VS, then you can use EnvDTE.

Search and filter files can be done either manually or using the DirectoryInfo structure. If I don’t get to the manual at all, I can write how.

I am writing as:

  static void Main(string[] args) { string root = @"D:\Trash"; List<string> files = Directory.GetFiles(@"D:\Trash", "*.cpp", SearchOption.AllDirectories).ToList(); List<string> relPath = new List<string>(); foreach (var file in files) { relPath.Add(file.Replace(root,"")); Console.WriteLine(file.Replace(root, "")); } } 

enter image description here

  • VS, as well as the location of the application is not tied to the essence of the issue. Or rather, the user on the workstation №1 application is installed in C: \ MyApp, and the reports in D: \ Work \ Reports \ The user on the workstation №2 application is in D: \ Program Files \ My_Work_Application, and the reports are in C: \ Work reports. Just in the program settings at each workplace, the user himself points the way to the reports, and at each instance he is DIFFERENT, but the program knows it (from the configuration). And this path is absolutely not necessarily tied to an EXE or AppData. - BlackWitcher
  • @BlackWitcher. Create Profil.ini and save all settings there. That is, the User specified the path to the working folder, programmatically saved to Profil.ini. When starting the program, read it. - Sergey_73
  • Yes, it's not about saving the configuration, because it is already stored in Application.config, and there the path to the reports is specified. The problem in another is how to get the difference between 2 absolute paths. - BlackWitcher
  • Another example of how no one reads a question ... - Pavel Mayorov
  • @BlackWitcher there below, there was an answer that you put a minus, read carefully. stackoverflow.com/questions/9042861/… - V. Dmitriy

Is it not easier then to use the standard %appdata% folder and store all your data in it?

 string Path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); string someReport = Path + "\\Shared\\Common\\BaseReports\\"; 

And to find the files, you need to run through all the folders here is an example:

 string file; string[] inf = Directory.GetFiles( someReport, "*.rpt", SearchOption.AllDirectories ); foreach ( var info in inf ) { //Что-то делаешь } 
  • And now, attention, the question is: what will your method contain in the variable info and how to get a relative path from it? :) - Pavel Mayorov
  • All your .rpt files - Sergey_73
  • @ Sergey_73. not easier, unfortunately. The base folder can change from workstation to workstation and sets its user. What is inside the base folder is invariable (conditionally not changed). - BlackWitcher
  • @ Sergey_73 and more specifically? - Pavel Mayorov
  • one
    @BlackWitcher because I argue that you have no problem with that. So, this "answer" does not answer your question. Moreover, it reduces your original problem to itself. - Pavel Mayorov