Monday, August 10, 2009

File.WriteAllText Quirks

Background

Today, in the course of adding a couple of features to a new tool, which I created last week, for internal use, I started to put the code behind its Save button through its paces, only to discover that the code displayed the following error message.

Access to the path d:\Path\FileName is denied.

Since I had recently opened the file in my text editor (UltraEdit) which I know, for certain, acquires exclusive access to files that you open for editing, I restarted the computer.

Alas, the problem persisted.

Analysis

The only difference in the environment between last week, when I wrote and tested the initial version of the program, and today, is that its output file is now marked Read Only, System, and Hidden. Since a companion Visual Basic script reads the very same file, with the same three flags set on it, I didn't expect trouble from the C# program that I wrote last week.

After wasting a couple of hours reading articles returned by several Google searches, I concluded that I might be the first person to identify this problem and write about it.

After tinkering with the file attributes, I discovered that the only way to get the File.WriteAllText() method to work was to temporarily remove all three attributes, although I suspect it's actually the Hidden attribute that is the offender.

Fortunately, this task was made much easier by the fact that I already had a FileInfoExtension class, which extends the standard System.IO.FileInfo class by adding a set of simple methods for setting, clearing, and restoring the Read Only file attribute. Leveraging my latest general purpose programming editor, UltraEdit, and the Visual Studio editor, it took only a few minutes to extend the class to cover the System, and Hidden attributes. For good measure, I also extended it to cover the Archive attribute. I decided to leave the remaining attributes for another day, since I don't have an immediate need for them.

In the C# program, the change required just seven new lines of code, highlighted in blue.

 FileInfoExtension fix = new FileInfoExtension ( strFQFN );
 /*
  --------------------------------------------------------
  The File.WriteAllText() method cannot see files unless
  their Hidden attribute is removed.
  --------------------------------------------------------
 */
 fix.SystemClear ( );
 fix.HiddenClear ( );
 fix.ReadOnlyClear ( );
 File.WriteAllText (
  strFQFN ,
  strData ,
  Encoding.ASCII );
 fix.ReadOnlySet ( );
 fix.SystemSet ( );
 fix.HiddenSet ( );

The first step is to create a new FileInfoExtension object, passing the name of the file, strFQFN, to its constructor. Next, the three attributes are cleared. The Archive attribute is ignored, because the call to File.WriteAllText() sets it to True. Finally, the three attributes are reset to to True. Since this is a tiny data file, this happens so fast that no user is likely to see the brief change.

I'll save a discussion of the FileInfoExtension class for another day. I'll just say that, if your code also needs a System.IO.FileInfo object to go with the same file, the FileInfoExtension class exposes one as a property.

 

No comments: