{"id":4653,"date":"2005-10-26T23:19:00","date_gmt":"2005-10-26T23:19:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/buckh\/2005\/10\/26\/displaying-the-sizes-and-dates-of-files-in-the-server\/"},"modified":"2005-10-26T23:19:00","modified_gmt":"2005-10-26T23:19:00","slug":"displaying-the-sizes-and-dates-of-files-in-the-server","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/buckh\/displaying-the-sizes-and-dates-of-files-in-the-server\/","title":{"rendered":"Displaying the sizes and dates of files in the server"},"content":{"rendered":"<p><P>Have you wished that the output of the dir command from tf.exe would show you the dates and sizes of the files like cmd.exe&#8217;s dir command?&nbsp; Even though&nbsp;tf.exe won&#8217;t do that in version 1, the version control API provides the call necessary.&nbsp; This little app is similar to my last post on <a href=\"http:\/\/blogs.msdn.com\/buckh\/archive\/2005\/10\/25\/484854.aspx\">displaying labels on a file<\/A>.&nbsp; You can find a simple example of creating a workspace, pending changes, and so forth in my September <a href=\"http:\/\/blogs.msdn.com\/buckh\/archive\/2005\/09\/09\/463287.aspx\">API example<\/A>.<\/P>\n<P>The GetItems() method is the key part of the app.&nbsp; Here&#8217;s the declaration on the VersionControlServer class.<\/P>\n<BLOCKQUOTE>\n<P dir=\"ltr\"><FONT face=\"Courier New\">public ItemSet GetItems(String path, RecursionType recursion)<\/FONT><\/P><\/BLOCKQUOTE>\n<P>For this overload of the GetItems() method, there&#8217;s no version parameter, so it defaults to get the Item objects for the latest version in the repository.&nbsp; There is another overload that takes the version, and you could pass &#8220;new WorkspaceVersionSpec(wsInfo.Name, wsInfo.OwnerName)&#8221; as the version to get the Item objects corresponding to the versions in the workspace.<\/P>\n<P>The first argument is the path on which we want data.&nbsp; That can be either a local path or a server path.<\/P>\n<P>The recursion parameter specifies how deep we want to go.&nbsp; If the path is a directory, specifying RecursionType.OneLevel retrieves only the items directly contained in that directory, just like specifying the wildcard &#8220;*&#8221; would.&nbsp; If the path is a file, there is no difference between one level of recursion and none because a file can&#8217;t have children.&nbsp; The default for this app is onle level of recursion, which is the same as what both cmd.exe&#8217;s dir command and tf.exe&#8217;s dir command use.<\/P>\n<P>If the user specifies \/r, the app passes RecursionType.Full.&nbsp; For a directory, that will return all of its descendants.&nbsp; If the path doesn&#8217;t match a directory, the server will recursively find all items under path that match.&nbsp; The path it uses is the directory portion of the path, and the pattern is the file name portion of the path.&nbsp; So, if the user specifies &#8220;c:\\project\\readme.txt \/r&#8221; the server will return all files called readme.txt underneath c:\\project, recursively.<\/P>\n<P>In the app, we only want the items for display, which is the Items property on the ItemSet object returned by GetItems().&nbsp; The other two properties on ItemSet, QueryPath and Pattern, indicate how the server used the specified path to do the matching.&nbsp; In our previous example of &#8220;c:\\project\\readme.txt \/r&#8221; the result would be&nbsp;QueryPath&nbsp;set to&nbsp;the server path corresponding to c:\\project and Pattern set to readme.txt.<\/P>\n<P>Here&#8217;s an example of running the app.<\/P>\n<BLOCKQUOTE>\n<P><FONT face=\"Courier New\">D:\\ws1&gt;D:\\code\\projects\\DirSize\\DirSize\\bin\\Debug\\DirSize.exe . \/r<BR>10\/25\/2005 11:40:25 AM&nbsp;&nbsp;&nbsp; &lt;DIR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $\/testproj<BR>10\/25\/2005 03:59:50 PM&nbsp;&nbsp;&nbsp; &lt;DIR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $\/testproj\/A<BR>10\/25\/2005 03:59:50 PM&nbsp;&nbsp;&nbsp; &lt;DIR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $\/testproj\/B<BR>10\/26\/2005 11:04:34 PM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7996 $\/testproj\/out.txt<BR>10\/25\/2005 04:55:50 PM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6 $\/testproj\/A\/a.txt<\/FONT><\/P>\n<P><FONT face=\"Courier New\">2 files, 3 folders, 8002 bytes<\/FONT><\/P><\/BLOCKQUOTE>\n<P>To build it, you can create a Windows console app in Visual Studio, drop this code into it, and add the following references to the VS project.<\/P>\n<BLOCKQUOTE>\n<P>Microsoft.TeamFoundation.Client<BR>Microsoft.TeamFoundation.Common<BR>Microsoft.TeamFoundation.VersionControl.Client<BR>Microsoft.TeamFoundation.VersionControl.Common<\/P><\/BLOCKQUOTE><PRE><SPAN>using<\/SPAN> System;\n<SPAN>using<\/SPAN> System.Globalization;\n<SPAN>using<\/SPAN> System.IO;\n<SPAN>using<\/SPAN> Microsoft.TeamFoundation;\n<SPAN>using<\/SPAN> Microsoft.TeamFoundation.Client;\n<SPAN>using<\/SPAN> Microsoft.TeamFoundation.VersionControl.Client;\n<SPAN>using<\/SPAN> Microsoft.TeamFoundation.VersionControl.Common;<\/p>\n<p><SPAN>namespace<\/SPAN> DirSize\n{\n    <SPAN>class<\/SPAN> Program\n    {\n        <SPAN>static<\/SPAN> <SPAN>void<\/SPAN> Main(<SPAN>string<\/SPAN>[] args)\n        {\n            <SPAN>\/\/ Check and get the arguments.<\/SPAN>\n            String path;\n            RecursionType recursion;\n            VersionControlServer sourceControl;\n            GetPathAndRecursion(args, <SPAN>out<\/SPAN> path, <SPAN>out<\/SPAN> recursion, <SPAN>out<\/SPAN> sourceControl);<\/p>\n<p>            Item[] items = <SPAN>null<\/SPAN>;\n            <SPAN>try<\/SPAN>\n            {\n                <SPAN>\/\/ Get the latest version of the information for the items.<\/SPAN>\n                ItemSet itemSet = sourceControl.GetItems(path, recursion);\n                items = itemSet.Items;\n            }\n            <SPAN>catch<\/SPAN> (TeamFoundationServerException e)\n            {\n                <SPAN>\/\/ We couldn&#8217;t contact the server, the item wasn&#8217;t found,<\/SPAN>\n                <SPAN>\/\/ or there was some other problem reported by the server,<\/SPAN>\n                <SPAN>\/\/ so we stop here.<\/SPAN>\n                Console.Error.WriteLine(e.Message);\n                Environment.Exit(<SPAN>1<\/SPAN>);\n            }<\/p>\n<p>            <SPAN>if<\/SPAN> (items.Length == <SPAN>0<\/SPAN>)\n            {\n                Console.WriteLine(<SPAN>&#8220;There are no items for &#8220;<\/SPAN> + path);\n            }\n            <SPAN>else<\/SPAN>\n            {\n                Array.Sort(items, Item.Comparer);<\/p>\n<p>                <SPAN>long<\/SPAN> totalBytes = <SPAN>0<\/SPAN>;\n                <SPAN>int<\/SPAN> numFiles = <SPAN>0<\/SPAN>, numFolders = <SPAN>0<\/SPAN>;\n                String format = <SPAN>&#8220;{0,-25} {1,-8} {2, 8} {3}&#8221;<\/SPAN>;\n                <SPAN>foreach<\/SPAN> (Item item <SPAN>in<\/SPAN> items)\n                {\n                    <SPAN>if<\/SPAN> (item.ItemType == ItemType.File)\n                    {<BR>                        <SPAN>\/\/ In addition to the information printed, the Item object has<BR>                        \/\/ the changeset version and MD5 hash of the file content as<BR>                        \/\/ properties on item<\/SPAN><SPAN>.<\/SPAN>\n                        numFiles++;\n                        totalBytes += item.ContentLength;\n                        Console.WriteLine(format,\n                                          item.CheckinDate.ToLocalTime().ToString(<SPAN>&#8220;G&#8221;<\/SPAN>),\n                                          String.Empty,\n                                          item.ContentLength,\n                                          item.ServerItem);\n                    }\n                    <SPAN>else<\/SPAN>\n                    {\n                        numFolders++;\n                        Console.WriteLine(format,\n                                          item.CheckinDate.ToLocalTime().ToString(<SPAN>&#8220;G&#8221;<\/SPAN>),\n                                          <SPAN>&#8220;&lt;DIR&gt;&#8221;<\/SPAN>,\n                                          String.Empty,\n                                          item.ServerItem);\n                    }\n                }<\/p>\n<p>                Console.WriteLine();\n                Console.WriteLine(<SPAN>&#8220;{0} files, {1} folders, {2} bytes&#8221;<\/SPAN>,\n                                  numFiles, numFolders, totalBytes);\n            }\n        }<\/p>\n<p>        <SPAN>private<\/SPAN> <SPAN>static<\/SPAN> <SPAN>void<\/SPAN> GetPathAndRecursion(String[] args,\n                                                <SPAN>out<\/SPAN> String path, <SPAN>out<\/SPAN> RecursionType recursion,\n                                                <SPAN>out<\/SPAN> VersionControlServer sourceControl)\n        {\n            <SPAN>if<\/SPAN> (args.Length &gt; <SPAN>2<\/SPAN> ||\n                args.Length == <SPAN>1<\/SPAN> &amp;&amp; args[<SPAN>0<\/SPAN>] == <SPAN>&#8220;\/?&#8221;<\/SPAN>)\n            {\n                Console.WriteLine(<SPAN>&#8220;Usage: dirsize&#8221;<\/SPAN>);\n                Console.WriteLine(<SPAN>&#8221;       dirsize [path] [\/r]&#8221;<\/SPAN>);\n                Console.WriteLine();\n                Console.WriteLine(<SPAN>&#8220;With no arguments, shows the size information for the current directory.&#8221;<\/SPAN>);\n                Console.WriteLine(<SPAN>&#8220;If a path is specified, it shows the size information for that path.&#8221;<\/SPAN>);\n                Console.WriteLine(<SPAN>&#8220;If \/r is specified, all of the children of the path will be included.&#8221;<\/SPAN>);\n                Console.WriteLine();\n                Console.WriteLine(<SPAN>&#8220;Examples: dirsize $\/secret&#8221;<\/SPAN>);\n                Environment.Exit(<SPAN>1<\/SPAN>);\n            }<\/p>\n<p>            <SPAN>\/\/ Figure out the server based on either the argument or the<\/SPAN>\n            <SPAN>\/\/ current directory.<\/SPAN>\n            WorkspaceInfo wsInfo = <SPAN>null<\/SPAN>;\n            <SPAN>if<\/SPAN> (args.Length &lt; <SPAN>1<\/SPAN> || args.Length == <SPAN>1<\/SPAN> &amp;&amp; args[<SPAN>0<\/SPAN>] == <SPAN>&#8220;\/r&#8221;<\/SPAN>)\n            {\n                path = Environment.CurrentDirectory;\n            }\n            <SPAN>else<\/SPAN>\n            {\n                path = args[<SPAN>0<\/SPAN>];\n                <SPAN>try<\/SPAN>\n                {\n                    <SPAN>if<\/SPAN> (!VersionControlPath.IsServerItem(path))\n                    {\n                        wsInfo = Workstation.Current.GetLocalWorkspaceInfo(path);\n                    }\n                }\n                <SPAN>catch<\/SPAN> (Exception e)\n                {\n                    <SPAN>\/\/ The user provided a bad path argument.<\/SPAN>\n                    Console.Error.WriteLine(e.Message);\n                    Environment.Exit(<SPAN>1<\/SPAN>);\n                }\n            }<\/p>\n<p>            <SPAN>if<\/SPAN> (wsInfo == <SPAN>null<\/SPAN>)\n            {\n                wsInfo = Workstation.Current.GetLocalWorkspaceInfo(Environment.CurrentDirectory);\n            }<\/p>\n<p>            <SPAN>\/\/ Stop if we couldn&#8217;t figure out the server.<\/SPAN>\n            <SPAN>if<\/SPAN> (wsInfo == <SPAN>null<\/SPAN>)\n            {\n                Console.Error.WriteLine(<SPAN>&#8220;Unable to determine the server.&#8221;<\/SPAN>);\n                Environment.Exit(<SPAN>1<\/SPAN>);\n            }<\/p>\n<p>            TeamFoundationServer tfs =\n                TeamFoundationServerFactory.GetServer(wsInfo.ServerName);\n                                                      <SPAN>\/\/ RTM: wsInfo.ServerUri.AbsoluteUri);<\/SPAN>\n            sourceControl = (VersionControlServer)tfs.GetService(<SPAN>typeof<\/SPAN>(VersionControlServer));<\/p>\n<p>            <SPAN>\/\/ Pick up the recursion, if supplied.  By default,<\/SPAN>\n            <SPAN>\/\/ we want item and its immediate children, if it is a folder.<\/SPAN>\n            <SPAN>\/\/ If the item is a file, then only the file will be returned.<\/SPAN>\n            recursion = RecursionType.OneLevel;\n            <SPAN>if<\/SPAN> (args.Length == <SPAN>1<\/SPAN> &amp;&amp; args[<SPAN>0<\/SPAN>] == <SPAN>&#8220;\/r&#8221;<\/SPAN> ||\n                args.Length == <SPAN>2<\/SPAN> &amp;&amp; args[<SPAN>1<\/SPAN>] == <SPAN>&#8220;\/r&#8221;<\/SPAN>)\n            {\n                recursion = RecursionType.Full;\n            }\n        }\n    }\n}\n<\/PRE><BR>[Update 11\/4\/2005] I added some explanation of the version used with the GetItems() call and the HashValue property of the Item class.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Have you wished that the output of the dir command from tf.exe would show you the dates and sizes of the files like cmd.exe&#8217;s dir command?&nbsp; Even though&nbsp;tf.exe won&#8217;t do that in version 1, the version control API provides the call necessary.&nbsp; This little app is similar to my last post on displaying labels on [&hellip;]<\/p>\n","protected":false},"author":94,"featured_media":10268,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[6,8,15],"class_list":["post-4653","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-source-control","tag-team-foundation","tag-tfs-api"],"acf":[],"blog_post_summary":"<p>Have you wished that the output of the dir command from tf.exe would show you the dates and sizes of the files like cmd.exe&#8217;s dir command?&nbsp; Even though&nbsp;tf.exe won&#8217;t do that in version 1, the version control API provides the call necessary.&nbsp; This little app is similar to my last post on displaying labels on [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts\/4653","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/users\/94"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/comments?post=4653"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts\/4653\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/media\/10268"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/media?parent=4653"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/categories?post=4653"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/tags?post=4653"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}