Why is .NET's File.Open with a UNC path making excessive SMB calls?

前端 未结 2 410
野性不改
野性不改 2021-02-01 02:29

I have a block of code that needs to open and read a lot of small text files from a NAS server using UNC paths. This code is part of a module that was originally written in C++

相关标签:
2条回答
  • 2021-02-01 02:58

    In short, File.Open calls new FileStream() and new FileStream() does a lot of calls:

    1. NormalisePath.

      String filePath = Path.NormalizePath(path, true, maxPath); // fullCheck: true
      

    leads to this code:

    1.a: Get full path:

        if (fullCheck) { ... 
            result = newBuffer.GetFullPathName();
    

    GetFullPathName() calls Win32Native.GetFullPathName one or two times (depending on the lentgh of resulting path).

    1.b. Trying to expand short path. Your path contains ~ char, so it looks like a candidate for a path expanding:

        if (mightBeShortFileName) {
            bool r = newBuffer.TryExpandShortFileName();
    

    as a result, Win32Native.GetLongPathName() is called.

    1. FileIoPermission.Demand() (for non-trusted only):

      // All demands in full trust domains are no-ops, so skip 
      if (!CodeAccessSecurityEngine.QuickCheckForAllDemands()) {
          ...
          new FileIOPermission(secAccess, control, new String[] { filePath }, false, false).Demand();
      
    2. Open fileStream (floppy strikes back;)):

       // Don't pop up a dialog for reading from an emtpy floppy drive
      int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
      try {
          ...
          _handle = Win32Native.SafeCreateFile(tempPath, fAccess, share, secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
      
    3. Win32Native.GetFileType()

    Not all of them would lead to smb request, but some will do. I've tried to reproduce chatty requests by debugging with source step-by-step (here's manual for enabling the .net source debugging) and checking the log after each step. Resuts are more similar to your's first listing. If you're really interested in finding the real issue, you'll have to do it yourself.

    UPD Note that I've checked current (.net 4.5.2) behavior. It was changed multiple times since 2.0 (e.g. FileIOPermission.Demand() originally was called for full-trusted code too), so it depends:)

    0 讨论(0)
  • 2021-02-01 03:11

    I don't really have a specific answer to why the .NET implementation is so chatty, but this behaviour would be due to the implementation of System.IO.FileStream as all that File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); is doing is passing the parameters to the FileStream constructor.

    public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share)
    {
        return new FileStream(path, mode, access, share);
    }
    

    Changing the behaviour of FileStream would mean that you would basically have to re-implement the FileStream class which will require a lot of effort.

    Your other more simpler alternative would be to create a native wrapper that calls the C++ code you gave. Then call the native wrapper from your C# code.

    0 讨论(0)
提交回复
热议问题