File.ReadAllLines() 无法读取由 Excel 打开的文件

File.ReadAllLines() fails to read from a file that is opened by Excel

假设我在 Excel 中打开一个文件,我知道我不能向它写入任何内容,因为它将 "locked" 由 Excel。

但是我可以读吗?或者这也不可能?

我正在使用以下代码:

If System.IO.File.Exists(file) Then
    output = System.IO.File.ReadAllLines(file).ToList
    If unique Then
        output = output.Distinct.ToList
    End If
Else
    output = New Generic.List(Of String)
End If

如何让它发挥作用?

我可以在 Excel 中以只读方式打开文件吗?那行得通吗?

很可能是其他程序锁定了文件,不允许其他程序执行此操作。如果是这种情况,您无能为力:/

查看此 SO,其中有更详细的解释:How do I open an already opened file with a .net StreamReader?

如果您是第一个打开它的程序,您可以以允许其他人打开的方式打开它:)

首先,您需要了解以下几点:

  • 只要 process/thread 打开文件,process/thread 就可以只读、只写或同时访问文件。查看 FileAccess Enum 了解更多信息。
  • 此外,process/thread 可以指定是否共享对文件的访问权限(例如,共享只读、只写、两者都共享,或者根本没有共享访问权限)。查看 FileShare Enum 了解更多。
  • 如果其他进程根本不共享对该文件的访问权限,那么您将无法访问该文件,无论它是用于读取还是写入。

现在 AFAIK,Excel 确实共享文件访问权限 用于读取 ,(但不共享用于写入)。因此,为了能够在 Excel 打开文件时访问该文件,您需要执行以下操作:

  • 只打开文件进行读取(因为您无权写入)。
  • 允许读取和写入文件因为另一个进程(即Excel)需要同时具有.

问题是,虽然 File.ReadAllLines() 以只读方式打开文件,但它 共享对文件用于写入(仅用于读取)。为了进一步说明,File.ReadAllLines() 默认使用具有以下值的 StreamReader internally 1, which --also internally-- uses a FileStream2

New FileStream(path, 
               FileMode.Open,
               FileAccess.Read,     ' This is good.
               FileShare.Read,      ' This is the problem (see the code below).
               ' ...

除非文件被另一个需要对文件 写入权限的进程打开,否则它会起作用。因此,您需要创建一个 FileStream 并为 FileAccessFileShare 枚举设置适当的值。因此,您的代码应如下所示:

Dim output As New List(Of String)
If IO.File.Exists(file) Then
    Using fs As New IO.FileStream(file,
                                  IO.FileMode.Open,
                                  IO.FileAccess.Read,       ' Open for reading only.
                                  IO.FileShare.ReadWrite)   ' Allow access for read/write.
        Using reader As New IO.StreamReader(fs)
            While Not reader.EndOfStream
                Dim currentLine As String = reader.ReadLine()
                If unique AndAlso output.Contains(currentLine) Then Continue While
                output.Add(currentLine)
            End While
        End Using
    End Using
End If

希望对您有所帮助。


参考文献:

1 InternalReadAllLines() source.

2 StreamReader internal constructor source.