{"id":566,"date":"2009-11-12T22:07:29","date_gmt":"2009-11-12T20:07:29","guid":{"rendered":"http:\/\/dev.bratched.fr\/fr\/jouer-avec-findfirstfile-et-findnextfile\/"},"modified":"2009-11-12T22:07:29","modified_gmt":"2009-11-12T20:07:29","slug":"jouer-avec-findfirstfile-et-findnextfile","status":"publish","type":"post","link":"https:\/\/bratched.com\/fr\/2009\/11\/12\/jouer-avec-findfirstfile-et-findnextfile\/","title":{"rendered":"Jouer avec FindFirstFile et FindNextFile"},"content":{"rendered":"<div class=\"jfdefaulttext\">\u00c9num\u00e9ration des fichiers dans .NET est facile. Tout le monde conna\u00eet la m\u00e9thode <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/wz42302f.aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">GetFiles<\/a> et vous pouvez \u00eatre tent\u00e9 d&rsquo;\u00e9crire du code comme ceci :<\/div>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:dfd1f4f2-1d69-4d2d-89e0-7b3bceec770c\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre>    var files = Directory.GetFiles(@\"c:windowssystem32\", \"*.dll\");\n    foreach (var file in files)\n    {\n        Console.WriteLine(file);\n    }\n<\/pre>\n<\/div>\n<p>Mais si vous regardez de plus pr\u00e8s, vous remarquerez que cette m\u00e9thode retourne un tableau de cha\u00eenes. Cela pourrait \u00eatre probl\u00e9matique si le r\u00e9pertoire que vous recherchez contient beaucoup de fichiers. La m\u00e9thode se bloque jusqu&rsquo;\u00e0 ce qu&rsquo;il effectue une recherche et une fois qu&rsquo;il termine il va charger tous les r\u00e9sultats dans la m\u00e9moire. Il serait beaucoup mieux si il vient de rentrer un IEnumerable. C&rsquo;est exactement ce que la m\u00e9thode <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd413233(VS.100).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">EnumerateFiles<\/a> dans .NET 4.0. Malheureusement dans .NET 3.5 il n&rsquo;y a rien pour le travail.<\/p>\n<p>Dans ce post, je vais montrer comment impl\u00e9menter cette fonctionnalit\u00e9 en utilisant les fonctions <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa364418(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">FindFirstFile<\/a> et <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa364428(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">FindNextFile<\/a> .<\/p>\n<p><!--more--><\/p>\n<p>Nous commen\u00e7ons par d\u00e9finir les prototypes de fonction native :<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:e55d321d-9622-4dc9-9557-361463671c93\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre>    internal sealed class Win32Native\n    {\n        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]\n        public struct WIN32_FIND_DATA\n        {\n            public uint dwFileAttributes;\n            public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;\n            public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;\n            public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;\n            public uint nFileSizeHigh;\n            public uint nFileSizeLow;\n            public uint dwReserved0;\n            public uint dwReserved1;\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]\n            public string cFileName;\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]\n            public string cAlternateFileName;\n        }\n\n        [DllImport(\"kernel32.dll\", CharSet = CharSet.Auto, SetLastError = true)]\n        public static extern SafeFindHandle FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);\n\n        [DllImport(\"kernel32.dll\", CharSet = CharSet.Auto, SetLastError = true)]\n        public static extern bool FindNextFile(SafeFindHandle hFindFile, out WIN32_FIND_DATA lpFindFileData);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true)]\n        public static extern bool FindClose(IntPtr hFindFile);\n    }\n<\/pre>\n<\/div>\n<p>Vous remarquerez peut-\u00eatre la classe SafeFindHandle utilis\u00e9e dans les signatures de m\u00e9thode. C&rsquo;est juste une simple classe d\u00e9riv\u00e9e de <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.runtime.interopservices.safehandle.aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">SafeHandle<\/a> qui s&rsquo;assurera que ce handle non manag\u00e9 est correctement ferm\u00e9 :<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:0eb754a0-9c1b-4b2f-8362-076d8d2f0de1\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre>    [SecurityCritical]\n    internal class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid\n    {\n        [SecurityCritical]\n        public SafeFindHandle() : base(true)\n        { }\n\n        [SecurityCritical]\n        protected override bool ReleaseHandle()\n        {\n            return Win32Native.FindClose(base.handle);\n        }\n    }\n<\/pre>\n<\/div>\n<p>Comme la documentation indique le handle cr\u00e9\u00e9 par <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa364418(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">FindFirstFile<\/a> doit \u00eatre ferm\u00e9 avec fonction <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa364413(VS.85).aspx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">FindClose<\/a> . Et enfin la mise en \u0153uvre de la m\u00e9thode EnumerateFiles :<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:a9635043-3e04-4473-a1b8-35683c2a9239\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre>    public static class DirectoryExtensions\n    {\n        public static IEnumerable&lt;string&gt; EnumerateFiles(string path, string searchPattern)\n        {\n            \/\/ TODO: validate input parameters\n            \n            string lpFileName = Path.Combine(path, searchPattern);\n            Win32Native.WIN32_FIND_DATA lpFindFileData;\n            var handle = Win32Native.FindFirstFile(lpFileName, out lpFindFileData);\n            if (handle.IsInvalid)\n            {\n                int hr = Marshal.GetLastWin32Error();\n                if (hr != 2 &amp;&amp; hr != 0x12)\n                {\n                    throw new Win32Exception(hr);\n                }\n                yield break;\n            }\n\n            if (IsFile(lpFindFileData))\n            {\n                var fileName = Path.Combine(path, lpFindFileData.cFileName);\n                yield return fileName;\n            }\n\n            while (Win32Native.FindNextFile(handle, out lpFindFileData))\n            {\n                if (IsFile(lpFindFileData))\n                {\n                    var fileName = Path.Combine(path, lpFindFileData.cFileName);\n                    yield return fileName;\n                }\n            }\n\n            handle.Dispose();\n        }\n\n        private static bool IsFile(Win32Native.WIN32_FIND_DATA data)\n        {\n            return 0 == (data.dwFileAttributes &amp; 0x10);\n        }\n    }\n<\/pre>\n<\/div>\n<p>La m\u00e9thode pourrait \u00eatre utilis\u00e9e comme ceci :<\/p>\n<div id=\"scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:2fffc9e3-e44c-4fa8-9b3a-7c7f33fd9707\" class=\"wlWriterSmartContent\" style=\"margin: 0px;padding: 0px;float: none\">\n<pre>    class Program\n    {\n        static void Main(string[] args)\n        {\n            var files = DirectoryExtensions.EnumerateFiles(@\"c:windowssystem32\", \"*.dll\");\n            foreach (var file in files)\n            {\n                Console.WriteLine(file);\n            }\n        }\n    }\n<\/pre>\n<\/div>\n<div class=\"clearfix\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u00c9num\u00e9ration des fichiers dans .NET est facile. Tout le monde conna\u00eet la m\u00e9thode GetFiles et vous pouvez \u00eatre tent\u00e9 d&rsquo;\u00e9crire du code comme ceci : var files = Directory.GetFiles(@\u00a0\u00bbc:windowssystem32&Prime;, \u00ab\u00a0*.dll\u00a0\u00bb); foreach (var file in files) { Console.WriteLine(file); } Mais si vous regardez de plus pr\u00e8s, vous remarquerez que cette m\u00e9thode retourne un tableau de cha\u00eenes. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[34],"tags":[40,41,42,43,35],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/posts\/566"}],"collection":[{"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/comments?post=566"}],"version-history":[{"count":0,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/posts\/566\/revisions"}],"wp:attachment":[{"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/media?parent=566"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/categories?post=566"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bratched.com\/fr\/wp-json\/wp\/v2\/tags?post=566"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}