{"id":55903,"date":"2008-03-28T00:30:00","date_gmt":"2008-03-28T00:30:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/03\/28\/hey-scripting-guy-how-can-i-incrementally-rename-files-based-on-the-file-creation-date\/"},"modified":"2008-03-28T00:30:00","modified_gmt":"2008-03-28T00:30:00","slug":"hey-scripting-guy-how-can-i-incrementally-rename-files-based-on-the-file-creation-date","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-incrementally-rename-files-based-on-the-file-creation-date\/","title":{"rendered":"Hey, Scripting Guy! How Can I Incrementally Rename Files Based on the File Creation Date?"},"content":{"rendered":"<p><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\" \/> <\/p>\n<p>Hey, Scripting Guy! I am trying to get my photos sorted in chronological order, even though \u2013 because they come from different cameras \u2013 they have different names. For example, one name type starts with DSC followed by a sequential number issued by one camera; another name type starts with IMG followed by a different sequential number. I want to rename the files in a folder based on the creation date and time to a name like &#8220;NY_2007_&#8221; + a number + &#8220;.jpg&#8221;. Is there a way to accomplish my renaming wishes?<\/p>\n<p>&#8212; EF<\/p>\n<p><img decoding=\"async\" border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\" \/><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\" \/><a href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><img decoding=\"async\" class=\"farGraphic\" title=\"Script Center\" border=\"0\" alt=\"Script Center\" align=\"right\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" height=\"288\" \/><\/a> <\/p>\n<p>Hey, EF. Before we launch into today\u2019s column we thought we\u2019d take a moment to update everyone on the status of the <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/games08.mspx\"><b>2008 Winter Scripting Games<\/b><\/a> prizes and Certificates of Excellence. As of today we have sent emails out to everyone who won a prize and\/or earned a Certificate of Excellence, and we have gotten back mailing addresses for <i>most<\/i> of those people. However, there <i>are<\/i> still a few holdouts; remember, if you don\u2019t send us your mailing address it\u2019s going to be very hard to get your prize\/certificate mailed out to you.<\/p>\n<table id=\"EID\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p><b>Note<\/b>. Well, unless you\u2019re Santa Claus: you can always get things to Santa simply by addressing them to <i>Santa Claus, c\/o The North Pole<\/i>. If you\u2019re <i>not<\/i> Santa Claus, however, then you should probably send us your mailing address.<\/p>\n<p>And yes, that\u2019s true even if you <i>are<\/i> the Easter Bunny, the Boogeyman, Scripting Guy Peter Costantini, or any other fictional character.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>At any rate, right now we\u2019re busy collating addresses and getting them in a format suitable for use with Microsoft\u2019s internal shipping tool; with any luck, we\u2019ll be able to start sending things out early next week. But be patient: we have nearly 400 prizes and well-over 700 certificates to send out. That\u2019s going to take a couple weeks for us to finish.<\/p>\n<table id=\"E6D\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p class=\"lastInCell\"><b>Note<\/b>. What\u2019s that? \u201cYou\u2019re the Scripting Guys; why don\u2019t you just get someone else to do all that work for you?\u201d Here\u2019s why we don\u2019t get someone else to do all that work for us: because we\u2019re the Scripting Guys. \u2018nuff said.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>Shipping out all these prizes takes even longer because we\u2019re supposed to keep doing all our regular work while we\u2019re at. Regular work like what? Well, like writing a script that can sort all the files in a folder in chronological order, and then rename each of those files:<\/p>\n<pre class=\"codeSample\">Const adVarChar = 200\nConst MaxCharacters = 255\n\nSet DataList = CreateObject(\"ADOR.Recordset\")\nDataList.Fields.Append \"FileName\", adVarChar, MaxCharacters\nDataList.Fields.Append \"FileDate\", adVarChar, MaxCharacters\nDataList.Open\n\nSet objFSO = CreateObject(\"Scripting.FileSystemObject\")\nSet objFolder = objFSO.GetFolder(\"C:\\New York\")\n\nSet colFiles = objFolder.Files\n\nFor Each objFile in colFiles\n    DataList.AddNew\n    DataList(\"FileName\") = objFile.Path\n    DataList(\"FileDate\") = objFile.DateCreated\n    DataList.Update\nNext\n\nDataList.Sort = \"FileDate\"\n\nDataList.MoveFirst\ni = 1\n\nDo Until DataList.EOF\n    If i &lt; 10 Then\n        x = CStr(\"000\" &amp; i)\n    ElseIf i &lt; 100 Then\n        x = CStr(\"00\" &amp; i)\n    ElseIf i &lt; 1000 Then\n        x = CStr(\"0\" &amp; i)\n    Else\n        x = i\n    End If\n\n    strNewName = \"C:\\New York\\NY_2007_\" &amp; x &amp; \".jpg\"\n    objFSO.MoveFile DataList.Fields.Item(\"FileName\"), strNewName\n\n    i = i + 1\n    DataList.MoveNext\nLoop\n<\/pre>\n<p>As it turns out, renaming files using VBScript is easy; the FileSystemObject can do that with a single line of code. It\u2019s also easy to retrieve the creation date for any given file; all we have to do is ask the FileSystemObject to return the value of the <b>DateCreated<\/b> property. What is difficult is taking a collection of files and sorting them in chronological order; that\u2019s because neither VBScript nor the FileSystemObject provide the ability to sort data. Needless to say, our ability to carry out this task depends in large part on our ability to sort data.<\/p>\n<p>That\u2019s where the \u201cdisconnected recordset\u201d comes in. We aren\u2019t going to talk about disconnected recordsets in any detail today; if you need some background information on these babies then take a peek at the <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/guide\/sas_ent_piij.mspx\"><b>Microsoft Windows 2000 Scripting Guide<\/b><\/a>. For now we\u2019ll just note that a disconnected recordset is a sort of \u201cvirtual\u201d database, a database that exists only in memory. Do we really <i>need<\/i> a database that exists only in memory? Believe it or not, we do: a virtual database like this provides a place where we can store our file paths and dates and then, more importantly, sort those files by creation date.<\/p>\n<p>In order to create a disconnected recordset we start by defining a pair of constants, adVarChar (which we\u2019ll use to create a database field that uses the variant datatype) and MaxCharacters (which we\u2019ll use to indicate that our database field can contain as many as 255 characters). After defining the two constants we create an instance of the <b>ADOR.Recordset<\/b> object (the object that lets us create a disconnected recordset); from there we then use the <b>Append<\/b> method to add two new fields to our recordset, one field named FileName and the other named FileDate:<\/p>\n<pre class=\"codeSample\">DataList.Fields.Append \"FileName\", adVarChar, MaxCharacters\nDataList.Fields.Append \"FileDate\", adVarChar, MaxCharacters\n<\/pre>\n<p>After we create these two fields we then call the <b>Open<\/b> method to open our disconnected recordset. At this point we\u2019re ready to start adding data to the recordset \u2026 or at least we would be if we actually <i>had<\/i> any data to add to the recordset.<\/p>\n<p>Fortunately for us, that\u2019s an easy problem to take care of. For starters, we create an instance of the <b>Scripting.FileSystemObject<\/b>, then use the <b>GetFolder<\/b> method to bind to the folder C:\\New York. That\u2019s what these two lines of code are for:<\/p>\n<pre class=\"codeSample\">Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\nSet objFolder = objFSO.GetFolder(\"C:\\New York\")\n<\/pre>\n<p>Once we\u2019re connected to the folder C:\\New York we retrieve a collection of all the files in that folder simply by setting an object reference to the folder\u2019s <b>Files<\/b> property:<\/p>\n<pre class=\"codeSample\">Set colFiles = objFolder.Files\n<\/pre>\n<p>Pretty easy, huh?<\/p>\n<p>Our next task is to retrieve the file path and creation date for each of these files, then add that information to the disconnected recordset. To that end we set up a For Each loop that loops us through each file in the collection. Inside that loop, we use this block of code to create a new record for the first file in the collection, setting the FileName field to the value of the file\u2019s <b>Path<\/b> property and the FileDate field to the value of the DateCreated property:<\/p>\n<pre class=\"codeSample\">DataList(\"FileName\") = objFile.Path\nDataList(\"FileDate\") = objFile.DateCreated\n<\/pre>\n<p>After we call the <b>Update<\/b> method to officially add the record to the recordset we go back to the top of the loop and repeat the process with the next file in the collection.<\/p>\n<p>Eventually we\u2019ll have created a record for each file in the folder C:\\New York. Once we\u2019ve done that our next chore is to sort all the files by creation date. That\u2019s a long and somewhat arduous process that involves a lot of \u2013 oh, sorry; as it turns out this isn\u2019t really all that long and arduous after all. In fact, all we have to do is call the <b>Sort<\/b> method followed by the name of the field we want to sort by:<\/p>\n<pre class=\"codeSample\">DataList.Sort = \"FileDate\"\n<\/pre>\n<p>At this point we have a disconnected recordset containing file paths and creation dates, a recordset in which the files have been sorted in chronological order. That can mean only one thing: it\u2019s time for lunch. We\u2019ll be back in an hour or so.<\/p>\n<p>OK, we\u2019re back. (Sorry we had to leave so abruptly, but today <i>is<\/i> Taco Salad Day.) As we were saying right before lunch, we\u2019re now ready to start renaming files. Or at least we will be in a few seconds; before we can do any of that we need to call the <b>MoveFirst<\/b> method to position the cursor at the beginning of our recordset, then set the value of a counter variable named i to 1:<\/p>\n<pre class=\"codeSample\">DataList.MoveFirst\ni = 1\n<\/pre>\n<p>OK, <i>now<\/i> we\u2019re ready to start renaming files. To do that, we start by setting up a Do Until loop designed to run until the recordset\u2019s <b>EOF<\/b> (end-of-file) property is True. (In other words, we want to keep looping until we run out of records.) The first thing we do inside the loop? This:<\/p>\n<pre class=\"codeSample\">If i &lt; 10 Then\n    x = CStr(\"000\" &amp; i)\nElseIf i &lt; 100 Then\n    x = CStr(\"00\" &amp; i)\nElseIf i &lt; 1000 Then\n    x = CStr(\"0\" &amp; i)\nElse\n    x= i\nEnd If\n<\/pre>\n<p>What we\u2019re doing here is \u2013 if necessary \u2013 adding leading zeros to our counter variable. For example, suppose i is less than 10 (the first condition in our If Then statement). In that case, we\u2019re going to assign three leading zeroes (000) plus the value of i to the variable x. If i is equal to 1 (as it will be the first time through the loop) then x will be equal to this:<\/p>\n<pre class=\"codeSample\">0001\n<\/pre>\n<p>If i is greater than 9 but less than 100 we\u2019ll add two leading zeroes. If i is greater than 99 but less than 999 we\u2019ll add one leading zero. And if i is greater than 999 we\u2019ll just assign x the value of i. Depending on the number of files in the folder that will give us values similar to this:<\/p>\n<pre class=\"codeSample\">0009\n0099\n0999\n9999\n<\/pre>\n<p>Why do we bother with all that? Mainly it\u2019s an aesthetic thing; that gives us a nice, neat directory listing that looks like this:<\/p>\n<pre class=\"codeSample\">NY_2007_0003.jpg\nNY_2007_0077.jpg\nNY_2007_0444.jpg\nNY_2007_1111.jpg\n<\/pre>\n<p>We like that better than a list that <i>doesn\u2019t<\/i> use leading zeroes:<\/p>\n<pre class=\"codeSample\">NY_2007_3.jpg\nNY_2007_77.jpg\nNY_2007_444.jpg\nNY_2007_1111.jpg\n<\/pre>\n<p>After we\u2019ve assigned a value to x we construct a new file name using this line of code:<\/p>\n<pre class=\"codeSample\">strNewName = \"C:\\New York\\NY_2007_\" &amp; x &amp; \".jpg\"\n<\/pre>\n<p>As you can see, there\u2019s nothing very fancy here: we\u2019re simply taking the string <i>C:\\New York\\NY_2007<\/i>, tacking on the value of x, then wrapping things up by adding the file extension <i>.jpg<\/i>. The first time through the loop that\u2019s going to give us a file path that looks like this:<\/p>\n<pre class=\"codeSample\">C:\\New York\\NY_2007_0001.jpg\n<\/pre>\n<p>We can then rename the first file in the collection (<b>DataList.Fields.Item(&#8220;FileName&#8221;)<\/b>) using a single line of code, just like we said we could:<\/p>\n<pre class=\"codeSample\">objFSO.MoveFile DataList.Fields.Item(\"FileName\"), strNewName\n<\/pre>\n<p>From there we increment the value of i by 1, call the <b>MoveNext<\/b> method to move to the next file in the recordset, and then repeat the process. When we\u2019re done we should have a folder filled with files similar to these:<\/p>\n<pre class=\"codeSample\">NY_2007_0001.jpg\nNY_2007_0002.jpg\nNY_2007_0003.jpg\nNY_2007_0004.jpg\n<\/pre>\n<p>Etc. etc.<\/p>\n<p>That should do it, EF; let us know if you have any questions. Remember, too that if you won a prize (or earned a certificate) during the Scripting Games you need to get your mailing address to us as soon as you can. That\u2019s especially true for anyone who won a <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/games08\/prizes.mspx\"><b>Dr. Scripto bobblehead doll<\/b><\/a>. If you don\u2019t claim your bobblehead soon, well, there will be plenty of other people more than willing to claim it for you.<\/p>\n<table id=\"EOAAC\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p><b>Note<\/b>. Plus several people who\u2019ve already <i>tried<\/i> to claim it. With that in mind we should point out that the Scripting Guys can\u2019t be sweet-talked into giving you a prize you didn\u2019t win.<\/p>\n<p>What\u2019s that? Can we be <i>bribed<\/i> into giving you a prize you didn\u2019t win? Well, that\u2019s very different now, isn\u2019t it? Let\u2019s talk about that the next time the Scripting Editor leaves town \u2026.<\/p>\n<p><b>Ed<\/b><b>itor\u2019s Note:<\/b> No, let\u2019s not.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I am trying to get my photos sorted in chronological order, even though \u2013 because they come from different cameras \u2013 they have different names. For example, one name type starts with DSC followed by a sequential number issued by one camera; another name type starts with IMG followed by a different [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[13,38,3,4,12,5],"class_list":["post-55903","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-dates-and-times","tag-files","tag-scripting-guy","tag-scripting-techniques","tag-storage","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I am trying to get my photos sorted in chronological order, even though \u2013 because they come from different cameras \u2013 they have different names. For example, one name type starts with DSC followed by a sequential number issued by one camera; another name type starts with IMG followed by a different [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55903","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=55903"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55903\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=55903"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=55903"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=55903"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}