FileStream was asked to open a device that was not a file
Asked Answered
F

1

11

I'm monitoring an FTP folder for orders which I then read into string array for further processing before deleting the file.

On the whole is works but occasionally I get the following exception:

FileStream was asked to open a device that was not a file. For support for devices like 'com1:' or 'lpt1:', call CreateFile, then use the FileStream constructors that take an OS handle as an IntPtr.. Stacktrace - at Microsoft.Win32.Win32Native.SafeCreateFile(String lpFileName, Int32 dwDesiredAccess, FileShare dwShareMode, SECURITY_ATTRIBUTES securityAttrs, FileMode dwCreationDisposition, Int32 dwFlagsAndAttributes, IntPtr hTemplateFile) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize, Boolean checkHost) at System.IO.StreamReader..ctor(String path, Encoding encoding) at System.IO.File.InternalReadAllLines(String path, Encoding encoding) at System.IO.File.ReadAllLines(String path)

However, looking at the filename and path it's nothing that I'd expect to throw such an error (like com1.txt)

\\xxx.xxx.xxx.xxx\mbftp\4392-24979.ORD

All filenames are in the same format [account]-[orderno].ORD, accounts are always 4 digit number.

Here is the code that throws the error:

try
{
    if (Directory.Exists(GetElementValue("FTPOrderFolder")))
    {
        if (File.Exists(fullOrderFilename))
        {
            if (File.GetLastAccessTime(fullOrderFilename) < DateTime.Now.AddSeconds(-2))
            {
                order = File.ReadAllLines(fullOrderFilename);
                if (order.Length > 0)
                {
                    File.Delete(fullOrderFilename);
                    NLogHelper.Debug(this, $"Deleted order file : {fullOrderFilename}");

                    return order;
                }
            }
        }
    }   
}
catch (Exception ex)
{
    NLogHelper.HandledException(this, ex);
}

The fact it's not a constant error is the thing I can't work out. I'm only accessing the file 2 seconds after it's last accessed so pretty sure it not a lock thing. It seems to show on 30% of order files being processed, the 70% working without an error.

Follicle answered 16/3, 2018 at 7:7 Comment(6)
Hard to guess. A proper UNC path is \\servername\sharename\dir\file.ext. If the network is so crickety that you have to resort to IP addresses to identify the machine then there are invariably more problems. It does matter to FileStream, .NET insists on knowing enough about the machine so it can properly identify what security zone it lives in. We can't help you get the network fixed, ask IT staff to assist you.Prevalent
The ftp machine is in the DMZ while the program isn't, hence the UNC path and the IP. The previous iteration of this program simply copied files from the FTP to the warehousing machine (File.Move) using the same paths and in 7 years never had an issue. Now the project needs to read the file to do some pre-procesing before passing it to the warehousing machine, hence why now we're reading the contents, but now this error occurs.Follicle
any solution on this issue?Insuperable
I am experiencing the same with PowerShell writing lots of files to an smb share...Gleiwitz
This is not an answer, but a suggestion. I can't comment because I'm too new. Its kind of naive, but could you consider copy the file from the ftp machine to the one running the code? Then, access the file locally, read, do some pre-procesing etc. Based on your comment, it could be network latency related.Vano
I'm experiencing this too in a highly parallised application simultaneously reading and writing across a network interface. Seems to be reproducable under very heavy load.Polson
L
0

A likely explanation for the error is that underlying network instability is interfering with your read operations. Consider the fallacies of distributed computing:

  1. The network is reliable;
  2. Latency is zero;
  3. Bandwidth is infinite;
  4. The network is secure;
  5. Topology doesn't change;
  6. There is one administrator;
  7. Transport cost is zero;
  8. The network is homogeneous;

Without knowing more about your network topology and infrastructure, I suggest the correct approach is to implement retry logic around your (network) I/O operations. Here's an extremely simple (naïve) approach:

int attempt = 0;
while (attempt++ < MaxRetries)
{
    try
    {
        if (Directory.Exists(GetElementValue("FTPOrderFolder")))
        {
            if (File.Exists(fullOrderFilename))
            {
                if (File.GetLastAccessTime(fullOrderFilename) < DateTime.Now.AddSeconds(-2))
                {
                    order = File.ReadAllLines(fullOrderFilename);
                    if (order.Length > 0)
                    {
                        File.Delete(fullOrderFilename);
                        NLogHelper.Debug(this, $"Deleted order file : {fullOrderFilename}");

                        return order;
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        if (attempt < MaxRetries) continue;
        NLogHelper.HandledException(this, ex);
    }
}

A more robust approach might use a resilience library like Polly.

Lordinwaiting answered 2/6 at 11:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.