How to exclude files from a FOR loop in a batch file

The other day, my colleague ran into an interesting problem… he needed to process a bunch of files in a directory using a batch file, and one by one, archive them and send them somewhere by FTP. The files were created programmatically by my code, and he ran into two problems:

  1. A race condition exists, since his batch file is invoked by a scheduler, and it could find a file while my program was still writing to it.
  2. He needed to pass a script file to ftp.exe, and there was no way to pass the actual filename in that script (besides generating the script inside the batch file, which is an horrendous hack).

Solving the second problem is obvious, although it wasn’t apparent to him, so sometimes it really does help if two people look at a problem. The batch file simply needed to move one file at a time, in the FOR loop, to a working directory; then the ftp command could use MPUT. (And send all the files in the directory, when there is only one file. This solves the problem because the script passed to ftp.exe no longer needs to contain the file name.)

Solving the first problem is also simple, but maybe not so obvious, especially considering that searching for it on Stack Overflow leads to several over-engineered solutions, so I’ll illustrate my solution here. The trick is to make the files hidden, and then use a dir command in the loop.

Here’s a simple example batch file that illustrates the solution.

  • Create a directory.
  • In the directory, create three files by right-clicking and selecting New Text Document. (You’ll end up with New Text Document.txt, New Text Document (2).txt, and New Text Document (3).txt.)
  • Now go to the file properties of the first file, New Text Document.txt, and set it to be a hidden file.

If you save the following as a batch file in the same directory and run it, it will print the names of the other files to the console, not the hidden file. This is because the hidden file attribute by definition hides files from the directory listing.

@echo off
for %%f in (dir *.txt) do echo %%f
pause

What you’ll get is this:

dir
New Text Document (2).txt
New Text Document (3).txt
Press any key to continue . . .

That was the solution, and if you got here by searching for how to exclude files from a batch FOR loop, that’s all you need to know. But for interest sake, here is how I created the hidden files in c#.

Since my code has full control of writing the files, I changed it to:

  • Write to a temporary file.
  • Set the hidden file attribute on the temporary file.
  • Move the file to the proper file location. (It will remain hidden.)
  • Set the file attributes normal. (Now we can be certain that the batch file will only find files that we have finished writing.)

Of course I’m leaving out exception handling here, and assume that you handle errors appropriately. Otherwise files could simply be lost if an exception is thrown while writing to a temporary file. My actual code in production handles this appropriately.

using System.IO;

namespace ContrivedExample
{
    class Example
    {
        public void SaveFile(string filename)
        {
            var tempfilename = Path.GetTempFileName();

            using (var writer = new StreamWriter(
                new FileStream(tempfilename, 
                    FileMode.Create, 
                    FileAccess.Write, 
                    FileShare.None)))
            {
                // File writing logic here
            }

            File.SetAttributes(tempfilename, FileAttributes.Hidden);
            File.Move(tempfilename, filename);
            File.SetAttributes(filename, FileAttributes.Normal);
        }
    }
}
Advertisements

About Jerome

I am a senior C# developer in Johannesburg, South Africa. I am also a recovering addict, who spent nearly eight years using methamphetamine. I write on my recovery blog about my lessons learned and sometimes give advice to others who have made similar mistakes, often from my viewpoint as an atheist, and I also write some C# programming articles on my programming blog.
This entry was posted in Programming, Work and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s