{"id":102433,"date":"2019-04-22T07:00:00","date_gmt":"2019-04-22T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=102433"},"modified":"2019-06-06T17:44:50","modified_gmt":"2019-06-07T00:44:50","slug":"20190422-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190422-00\/?p=102433","title":{"rendered":"A little program to look for files with inconsistent line endings"},"content":{"rendered":"<p>I wrote this little program to look for files with inconsistent line endings. Maybe you&#8217;ll find it useful. Probably not, but I&#8217;m posting it anyway. <\/p>\n<pre>\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\n\nclass Program\n{\n    static IEnumerable&lt;FileInfo&gt; EnumerateFiles(string dir)\n    {\n        var info = new System.IO.DirectoryInfo(dir);\n        foreach (var f in info.EnumerateFileSystemInfos(\n                           \"*.*\", SearchOption.TopDirectoryOnly))\n        {\n            if (f.Attributes.HasFlag(FileAttributes.Hidden))\n            {\n                continue;\n            }\n\n            if (f.Attributes.HasFlag(FileAttributes.Directory))\n            {\n                switch (f.Name.ToLower())\n                {\n                    case \"bin\":\n                    case \"obj\":\n                        continue;\n                }\n\n                foreach (var inner in EnumerateFiles(f.FullName))\n                {\n                    yield return inner;\n                }\n            }\n            else\n            {\n                yield return (FileInfo)f;\n            }\n        }\n    }\n\n    \/\/ Starting in the current directory, enumerate files\n    \/\/ (see EnumerateFiles for criteria), and report what\n    \/\/ type of line ending each file uses.\n\n    static void Main()\n    {\n        foreach (var f in EnumerateFiles(\".\"))\n        {\n            \/\/ Skip obvious binary files.\n            switch (f.Extension.ToLower())\n            {\n                case \".png\":\n                case \".jpg\":\n                case \".gif\":\n                case \".wmv\":\n                    continue;\n            }\n\n            int line = 0; \/\/ total number of lines found\n            int cr = 0;   \/\/ number of lines that end in CR\n            int crlf = 0; \/\/ number of lines that end in CRLF\n            int lf = 0;   \/\/ number of lines that end in LF\n\n            var stream = new FileStream(\n                     f.FullName, FileMode.Open, FileAccess.Read);\n            using (var br = new BinaryReader(stream))\n            {\n                \/\/ Slurp the entire file into memory.\n                var bytes = br.ReadBytes((int)f.Length);\n                for (int i = 0; i &lt; bytes.Length; i++)\n                {\n                    if (bytes[i] == '\\r')\n                    {\n                        if (i + 1 &lt; bytes.Length &amp;&amp;\n                            bytes[i+1] == '\\n')\n                        {\n                            line++;\n                            crlf++;\n                            i++;\n                        }\n                        else\n                        {\n                            line++;\n                            cr++;\n                        }\n                    }\n                    else if (bytes[i] == '\\n')\n                    {\n                        lf++;\n                        line++;\n                    }\n                }\n            }\n\n            if (cr == line)\n            {\n                Console.WriteLine(\"{0}, {1}\", f.FullName, \"CR\");\n            }\n            else if (crlf == line)\n            {\n                Console.WriteLine(\"{0}, {1}\", f.FullName, \"CRLF\");\n            }\n            else if (lf == line)\n            {\n                Console.WriteLine(\"{0}, {1}\", f.FullName, \"LF\");\n            }\n            else\n            {\n                Console.WriteLine(\"{0}, {1}, {2}, {3}, {4}\",\n                              f.FullName, \"Mixed\", cr, lf, crlf);\n            }\n        }\n    }\n}\n<\/pre>\n<p>The <code>Enumerate&shy;Files<\/code> method recursively enumerates the contents of the directory, but skips over hidden files, hidden directories, and directories with specific names. <\/p>\n<p>The main program takes the files enumerated by <code>Enumerate&shy;Files<\/code>, ignores certain known binary file types, and for the remaining files, counts the number of lines and how many of them use any particular line terminator. <\/p>\n<p>If the file&#8217;s lines all end the same way, then that line terminator is reported with the file name. Otherwise, the file is reported as <i>Mixed<\/i> and the number of lines of each type is reported. <\/p>\n<p>I use this little program when chasing down line terminator inconsistencies. Maybe that&#8217;s not something you have to deal with, in which case lucky you. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Something I wrote.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-102433","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Something I wrote.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102433","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=102433"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102433\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=102433"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=102433"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=102433"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}