-1

Given this code snippet:

public IEnumerable<IFileInfo> GetFiles(string searchPattern)
{
    return this.DirectoryInfo
               .GetFiles(searchPattern)
               .Select(fileInfo => new FileInfoWrapper(fileInfo.FullName));
}

Suppose that the physical disk have bad sectors. This code is called wrapped into a try/catch clause.

try
{
    var files = this.GetFiles("*");
    // ...
}
catch (IOException ex)
{
    // This call writes a new entry on Windows EventLog
    // - The text written is ex.Message plus ex.Stacktrace value in this case.
    new LogEntry((int)GlobalEventLogId.FileIoError, ex)
    {
        Source = Assembly.GetExecutingAssembly().GetName().Name,
        EntryType = LogEntryType.Error,
    }.Write(); 
}

How can I determine what file is corrupt if the code raises IOException with text: Data Error (Cyclic Rendundancy check)?

HuorSwords
  • 2,225
  • 1
  • 21
  • 34
  • You never read a file. It is disk's MFT that is corrupted. A very serious problem, it belongs on the scrap heap. If you need to rescue data from the disk drive then ask a question about it at superuser.com – Hans Passant Oct 13 '14 at 16:11
  • @HansPassant, thank you for your comments. In this case I don't want to rescue data, just identify what files are corrupt and report it when my process (that use this files) has encounter a problem. – HuorSwords Oct 14 '14 at 05:59

1 Answers1

1

I would modify GetFiles() to use yield return and wrapping the new FileInfoWrapper() bit with a try/catch and re-throw with a custom exception. Something like this:

foreach(var fileInfo in DirectoryInfo.GetFiles(searchPattern))
{
    try
    {
        yield return new FileInfoWrapper(fileInfo.FullName);
    }
    catch(Exception ex)
    {
        throw new MyException(fileInfo.FullName, ex);
    }
}

If you want to stick with LINQ, you could use Microsoft's Ix-Main package which has a Catch extension, but I think this makes for some pretty ugly code:

this.DirectoryInfo
       .GetFiles(searchPattern)
       .SelectMany(fileInfo =>
           EnumerableEx.Return(fileInfo)
             .Select(fi => new FileInfoWrapper(fi.FullName))
             .Catch<FileInfoWrapper, Exception>(ex =>
                 { throw new MyException(fileInfo.FullName, ex); }));
Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
  • I don't think this will work, since DirectoryInfo.GetFiles tries to get _all files_ before returning. You should use `DirectoryInfo.EnumerateFiles` instead. – Chris Dunaway Oct 13 '14 at 17:37
  • `EnumerateFiles` is definitely preferred for LINQ-to-FS, but I don't think it matters in this situation so I kept the code as close to his as possible. Either way, you would not know which file name caused an exception if it was coming out of `GetFiles`. – Cory Nelson Oct 13 '14 at 18:21
  • Agreed, however my point was that using `GetFiles`, the exception would occur before the code ever reached your `yield return` whereas using `EnumerateFiles` might just allow some files to be processed before the exception. But I agree that it would be unlikely that there would be a way to know what the offending filename is. – Chris Dunaway Oct 13 '14 at 20:50
  • I think that is a good idea. I use the `foreach` version, I think that is more clear than using LINQ in this case. Just as a comment... Visual Studio mark as error when you try to `yield` values inside a `try/catch` block. – HuorSwords Oct 14 '14 at 05:55