Pergunta

Tenho que desenvolver um aplicativo que analise um arquivo de log e envie dados específicos para um servidor.Ele deve rodar em Linux e Windows.

O problema aparece quando quero testar o sistema de rolagem de log (que anexa .1 ao nome do cria um novo com o mesmo nome).No Windows (ainda não testei no Linux) não consigo renomear um arquivo que abri com std::ifstream() (acesso exclusivo?) mesmo se eu abri-lo no "modo de entrada" (ios::in) .

Existe uma maneira multiplataforma de abrir arquivos de maneira não exclusiva?

Foi útil?

Solução

Existe uma maneira de abrir arquivos de forma não exclusiva,

Sim, usando Win32, passando os vários sinalizadores FILE_SHARE_Xxxx para CreateFile.

é multiplataforma?

Não, requer código específico da plataforma.

Devido a preocupações irritantes de compatibilidade com versões anteriores (aplicativos DOS, sendo de tarefa única, assumem que nada pode excluir um arquivo deles, ou seja,que eles podem fclose() e então fopen() sem que nada dê errado;O Win16 preservou essa suposição para facilitar a portabilidade de aplicativos DOS, o Win32 preservou essa suposição para facilitar a portabilidade de aplicativos Win16, e é horrível), o padrão do Windows é abrir arquivos exclusivamente.

A infraestrutura do sistema operacional subjacente suporta exclusão/renomeação de arquivos abertos (embora eu acredite que tenha a restrição de que arquivos mapeados na memória não possam ser excluídos, o que acho que não é uma restrição encontrada no *nix), mas a semântica de abertura padrão não.

C++ não tem noção de nada disso;o ambiente operacional C++ é praticamente igual ao ambiente operacional DOS – nenhum outro aplicativo é executado simultaneamente, portanto, não há necessidade de controlar o compartilhamento de arquivos.

Outras dicas

Não é a operação de leitura que exige o modo exclusivo, é a renomeação, porque é essencialmente o mesmo que mover o arquivo para um novo local.

Não tenho certeza, mas não acho que isso possa ser feito.Em vez disso, tente copiar o arquivo e, posteriormente, excluir/substituir o arquivo antigo quando ele não for mais lido.

A semântica do sistema de arquivos Win32 exige que um arquivo renomeado não esteja aberto (em nenhum modo) no momento da renomeação.Você precisará fechar o arquivo, renomeá-lo e criar o novo arquivo de log.

A semântica do sistema de arquivos Unix permite renomear um arquivo que está aberto porque o nome do arquivo é apenas um ponteiro para o inode.

Se você está apenas lendo o arquivo, sei que isso pode ser feito com a API do Windows CreateFile.Basta especificar file_share_delete | File_share_read | File_share_write como entrada para DWSharemode.

Infelizmente, isso não é multiplataforma.Mas pode haver algo semelhante para Linux.

Consulte msdn para obter mais informações sobre CreateFile.

EDITAR:Apenas uma nota rápida sobre o comentário de Greg Hewgill.Acabei de testar com o material FILE_SHARE* (tenha 100% de certeza).E é possível excluir e renomear arquivos no Windows se você abrir somente leitura e especificar os parâmetros FILE_SHARE*.

Eu garantiria que você não mantivesse os arquivos abertos.Isso leva a coisas estranhas se o seu aplicativo travar, por exemplo.O que eu faria:

  1. Resumo (leitura/gravação/rolagem para um novo arquivo) em uma classe e organize o fechamento do arquivo quando quiser passar para um novo nessa classe.(esta é a maneira mais simples e, como você já possui o código de rollover, já está na metade do caminho.)
  2. Se você deve ter vários pontos de acesso de leitura/gravação, precisa de todos os recursos do fstreams e não deseja escrever um wrapper completo, então a única solução multiplataforma que consigo pensar é sempre fechar o arquivo quando você não precisar dele e faça com que o código de rollover tente adquirir acesso exclusivo ao arquivo algumas vezes quando ele precisar ser rollover antes de desistir.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top