132
|
1 /*******************************************************************************
|
|
2
|
|
3 copyright: Copyright (c) 2004 Kris Bell. All rights reserved
|
|
4
|
|
5 license: BSD style: $(LICENSE)
|
|
6
|
|
7 version: Jun 2004: Initial release
|
|
8 version: Dec 2006: Pacific release
|
|
9
|
|
10 author: Kris
|
|
11
|
|
12 *******************************************************************************/
|
|
13
|
|
14 module tango.io.FileScan;
|
|
15
|
|
16 public import tango.io.FilePath;
|
|
17
|
|
18 private import tango.core.Exception;
|
|
19
|
|
20 /*******************************************************************************
|
|
21
|
|
22 Recursively scan files and directories, adding filtered files to
|
|
23 an output structure as we go. This can be used to produce a list
|
|
24 of subdirectories and the files contained therein. The following
|
|
25 example lists all files with suffix ".d" located via the current
|
|
26 directory, along with the folders containing them:
|
|
27 ---
|
|
28 auto scan = new FileScan;
|
|
29
|
|
30 scan (".", ".d");
|
|
31
|
|
32 Stdout.formatln ("{} Folders", scan.folders.length);
|
|
33 foreach (folder; scan.folders)
|
|
34 Stdout.formatln ("{}", folder);
|
|
35
|
|
36 Stdout.formatln ("\n{} Files", scan.files.length);
|
|
37 foreach (file; scan.files)
|
|
38 Stdout.formatln ("{}", file);
|
|
39 ---
|
|
40
|
|
41 This is unlikely the most efficient method to scan a vast number of
|
|
42 files, but operates in a convenient manner
|
|
43
|
|
44 *******************************************************************************/
|
|
45
|
|
46 class FileScan
|
|
47 {
|
|
48 alias sweep opCall;
|
|
49
|
|
50 FilePath[] fileSet;
|
|
51 char[][] errorSet;
|
|
52 FilePath[] folderSet;
|
|
53
|
|
54 /***********************************************************************
|
|
55
|
|
56 Alias for Filter delegate. Accepts a FilePath & a bool as
|
|
57 arguments and returns a bool.
|
|
58
|
|
59 The FilePath argument represents a file found by the scan,
|
|
60 and the bool whether the FilePath represents a folder.
|
|
61
|
|
62 The filter should return true, if matched by the filter. Note
|
|
63 that returning false where the path is a folder will result
|
|
64 in all files contained being ignored. To always recurse folders,
|
|
65 do something like this:
|
|
66 ---
|
|
67 return (isDir || match (fp.name));
|
|
68 ---
|
|
69
|
|
70 ***********************************************************************/
|
|
71
|
|
72 alias FilePath.Filter Filter;
|
|
73
|
|
74 /***********************************************************************
|
|
75
|
|
76 Return all the errors found in the last scan
|
|
77
|
|
78 ***********************************************************************/
|
|
79
|
|
80 public char[][] errors ()
|
|
81 {
|
|
82 return errorSet;
|
|
83 }
|
|
84
|
|
85 /***********************************************************************
|
|
86
|
|
87 Return all the files found in the last scan
|
|
88
|
|
89 ***********************************************************************/
|
|
90
|
|
91 public FilePath[] files ()
|
|
92 {
|
|
93 return fileSet;
|
|
94 }
|
|
95
|
|
96 /***********************************************************************
|
|
97
|
|
98 Return all directories found in the last scan
|
|
99
|
|
100 ***********************************************************************/
|
|
101
|
|
102 public FilePath[] folders ()
|
|
103 {
|
|
104 return folderSet;
|
|
105 }
|
|
106
|
|
107 /***********************************************************************
|
|
108
|
|
109 Sweep a set of files and directories from the given parent
|
|
110 path, with no filtering applied
|
|
111
|
|
112 ***********************************************************************/
|
|
113
|
|
114 FileScan sweep (char[] path, bool recurse=true)
|
|
115 {
|
|
116 return sweep (path, cast(Filter) null, recurse);
|
|
117 }
|
|
118
|
|
119 /***********************************************************************
|
|
120
|
|
121 Sweep a set of files and directories from the given parent
|
|
122 path, where the files are filtered by the given suffix
|
|
123
|
|
124 ***********************************************************************/
|
|
125
|
|
126 FileScan sweep (char[] path, char[] match, bool recurse=true)
|
|
127 {
|
|
128 return sweep (path, (FilePath fp, bool isDir)
|
|
129 {return isDir || fp.suffix == match;}, recurse);
|
|
130 }
|
|
131
|
|
132 /***********************************************************************
|
|
133
|
|
134 Sweep a set of files and directories from the given parent
|
|
135 path, where the files are filtered by the provided delegate
|
|
136
|
|
137 ***********************************************************************/
|
|
138
|
|
139 FileScan sweep (char[] path, Filter filter, bool recurse=true)
|
|
140 {
|
|
141 errorSet = null, fileSet = folderSet = null;
|
|
142 return scan (new FilePath(path), filter, recurse);
|
|
143 }
|
|
144
|
|
145 /***********************************************************************
|
|
146
|
|
147 Internal routine to locate files and sub-directories. We
|
|
148 skip entries with names composed only of '.' characters.
|
|
149
|
|
150 ***********************************************************************/
|
|
151
|
|
152 private FileScan scan (FilePath folder, Filter filter, bool recurse)
|
|
153 {
|
|
154 try {
|
|
155 auto paths = folder.toList (filter);
|
|
156
|
|
157 auto count = fileSet.length;
|
|
158 foreach (path; paths)
|
|
159 if (! path.isFolder)
|
|
160 fileSet ~= path;
|
|
161 else
|
|
162 if (recurse)
|
|
163 scan (path, filter, recurse);
|
|
164
|
|
165 // add packages only if there's something in them
|
|
166 if (fileSet.length > count)
|
|
167 folderSet ~= folder;
|
|
168
|
|
169 } catch (IOException e)
|
|
170 errorSet ~= e.toString;
|
|
171 return this;
|
|
172 }
|
|
173 }
|
|
174
|
|
175
|
|
176 /*******************************************************************************
|
|
177
|
|
178 *******************************************************************************/
|
|
179
|
|
180 debug (FileScan)
|
|
181 {
|
|
182 import tango.io.Stdout;
|
|
183
|
|
184 void main()
|
|
185 {
|
|
186 auto scan = new FileScan;
|
|
187
|
|
188 scan (".");
|
|
189
|
|
190 Stdout.formatln ("{} Folders", scan.folders.length);
|
|
191 foreach (folder; scan.folders)
|
|
192 Stdout (folder).newline;
|
|
193
|
|
194 Stdout.formatln ("\n{} Files", scan.files.length);
|
|
195 foreach (file; scan.files)
|
|
196 Stdout (file).newline;
|
|
197
|
|
198 Stdout.formatln ("\n{} Errors", scan.errors.length);
|
|
199 foreach (error; scan.errors)
|
|
200 Stdout (error).newline;
|
|
201 }
|
|
202 }
|