O bloco de notas vence todos eles?

134

Em um sistema Windows Server 2012 R2, um programa Kotlin usa FileChannel.tryLock()para manter um bloqueio exclusivo em um arquivo, como este:

val fileRw = RandomAccessFile(file, "rw")
fileRw.channel.tryLock()

Com esse bloqueio, não consigo abrir o arquivo com:

  • Prancheta
  • Notepad ++
  • Programaticamente com C #, para qualquer valor de FileShare:

    using (var fileStream = new FileStream(processIdPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (var textReader = new StreamReader(fileStream))
    {
        textReader.ReadToEnd();
    }
  • Na linha de comando, o typecomando:

    C:\some-directory>type file.txt
    The process cannot access the file because another process has locked a portion of the file.
  • Internet Explorer (sim, eu estava desesperado)

Eu posso abri-lo com o bloco de notas.

Como diabos o Bloco de Notas é capaz de abrir um arquivo bloqueado que nada mais pode?

MonoThreaded
fonte

Respostas:

202

O Bloco de Notas lê os arquivos mapeando-os primeiro na memória, em vez de usar os mecanismos "habituais" de leitura de arquivos, presumivelmente usados ​​pelos outros editores que você tentou. Esse método permite a leitura de arquivos, mesmo que eles tenham bloqueios exclusivos baseados em intervalo.

Você pode conseguir o mesmo em C # com algo parecido com:

using (var f = new FileStream(processIdPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var m = MemoryMappedFile.CreateFromFile(f, null, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, true))
using (var s = m.CreateViewStream(0, 0, MemoryMappedFileAccess.Read))
using (var r = new StreamReader(s))
{
    var l = r.ReadToEnd();
    Console.WriteLine(l);
}
Irídio
fonte
58
Confirmado em mais detalhes por Raymond Chen, da Microsoft : Para carregar um arquivo, o Bloco de Notas mapeia uma exibição do arquivo como um arquivo mapeado na memória e o usa como fonte. O código descobre a codificação, executa uma conversão de página de código em UTF-16LE, se necessário, coloca o resultado em um bloco de memória e, em seguida, usa a mensagem EM_SETHANDLE para entregar esse bloco inteiro ao controle de edição.
Stevoisiak