Lendo arquivos
Aula 42 do curso de PowerShell sobre leitura de arquivos. Você aprenderá a usar o cmdlet Get-Content, a diferença entre leitura como array e como string única com -Raw, como processar linha a linha, e como lidar com codificações de caractere.
Nesta aula, vamos explorar uma das operações mais comuns em scripts: a leitura de arquivos. Dominar a leitura de arquivos é essencial para processar logs, configurações, dados de entrada e muito mais. O PowerShell oferece o cmdlet Get-Content, que é a ferramenta principal para essa tarefa. Vamos entender suas variações, parâmetros e boas práticas para evitar armadilhas comuns, como problemas de encoding e desempenho.
Além de ler o conteúdo, você aprenderá a controlar como os dados são apresentados: como um array de linhas, como uma única string ou processando linha por linha. Isso influencia diretamente como você manipula os dados no seu script. Vamos também discutir a importância de especificar a codificação correta para evitar caracteres corrompidos.
Get-Content
O cmdlet Get-Content é o equivalente ao cat do Linux ou ao type do CMD. Ele lê um arquivo e retorna seu conteúdo. Por padrão, ele retorna um array de strings, onde cada elemento é uma linha do arquivo. Isso é extremamente útil para processar arquivos linha por linha.
Vamos começar com um exemplo simples. Suponha que temos um arquivo chamado exemplo.txt com o seguinte conteúdo:
# exemplo.txt
Linha 1
Linha 2
Linha 3Para ler o arquivo, usamos:
Get-Content -Path C:\temp\exemplo.txtIsso exibirá cada linha no console. O resultado é um array de strings, o que significa que podemos armazená-lo em uma variável e acessar linhas específicas por índice (começando em 0).
$linhas = Get-Content -Path C:\temp\exemplo.txt
$linhas[0] # Retorna "Linha 1"
$linhas.Count # Retorna 3O parâmetro -Path aceita curingas, permitindo ler vários arquivos de uma vez. Por exemplo, para ler todos os arquivos .log de um diretório:
Get-Content -Path C:\logs\*.logNesse caso, o conteúdo de todos os arquivos é concatenado em um único array, sem separadores entre arquivos. Se precisar saber de qual arquivo veio cada linha, é melhor usar outros cmdlets como Get-ChildItem em conjunto.
-Raw
Às vezes, você quer ler o arquivo como uma única string, sem divisão em linhas. Para isso, use o parâmetro -Raw. Isso é útil quando você precisa tratar o conteúdo como um todo, por exemplo, para fazer uma substituição global ou para analisar XML, JSON ou outros formatos que não são linha a linha.
$conteudoCompleto = Get-Content -Path C:\temp\exemplo.txt -RawAgora $conteudoCompleto é uma string única que contém tudo, incluindo as quebras de linha. Você pode verificar:
$conteudoCompleto.GetType().Name # String
$conteudoCompleto.Length # Número total de caracteresUma aplicação comum é substituir texto em todo o arquivo de uma vez:
$conteudo = Get-Content -Path arquivo.txt -Raw
$conteudo = $conteudo -replace 'foo', 'bar'
Set-Content -Path arquivo.txt -Value $conteudoSem -Raw, o -replace seria aplicado a cada linha separadamente, o que pode ser ineficiente e causar problemas se a substituição envolver quebras de linha.
Lendo linha a linha
Embora Get-Content retorne um array de linhas, carregar um arquivo inteiro na memória pode ser problemático para arquivos muito grandes. Para processar arquivos grandes de forma eficiente, você pode usar o parâmetro -ReadCount ou um loop foreach com o pipeline. O PowerShell permite que você processe cada linha à medida que é lida, sem armazenar tudo na memória.
Uma abordagem comum é usar o pipeline:
Get-Content -Path C:\logs\grande.log | ForEach-Object {
# $_ contém a linha atual
if ($_ -match 'erro') {
Write-Host "Encontrado: $_"
}
}Nesse exemplo, cada linha é processada individualmente e descartada em seguida. Isso é eficiente para arquivos com milhões de linhas.
Outra opção é usar -ReadCount para ler um número específico de linhas por vez. O padrão é 1, mas você pode definir um valor maior para reduzir o número de chamadas ao disco. Por exemplo, para ler 1000 linhas por vez:
Get-Content -Path arquivo.txt -ReadCount 1000 | ForEach-Object {
# $_ é um array com até 1000 linhas
foreach ($linha in $_) {
# processa cada linha
}
}Essa técnica é útil quando você precisa de um lote de linhas para processamento em conjunto, como para inserir em um banco de dados.
Também é importante conhecer a diferença entre Get-Content e o método [System.IO.File]::ReadLines() do .NET. O método ReadLines() também retorna um enumerador que lê linha por linha, mas é mais rápido em alguns cenários. Você pode usá-lo assim:
[System.IO.File]::ReadLines("C:\temp\arquivo.txt") | ForEach-Object {
# processa a linha
}Para a maioria dos scripts, Get-Content é suficiente, mas para arquivos extremamente grandes, considere usar ReadLines().
Encoding
Encoding (codificação) é a forma como os caracteres são representados em bytes. O PowerShell usa por padrão a codificação do sistema (geralmente UTF-8 sem BOM no PowerShell 7, e ANSI no Windows PowerShell 5.1). Ao ler arquivos com codificações diferentes, você pode obter caracteres corrompidos. Portanto, é essencial especificar a codificação correta ao ler e escrever arquivos.
O parâmetro -Encoding do Get-Content permite definir a codificação esperada. Os valores comuns incluem:
utf8- UTF-8 (com ou sem BOM, dependendo da versão)ascii- ASCIIunicode- UTF-16 LEbigendianunicode- UTF-16 BEutf8BOM- UTF-8 com BOM (disponível no PowerShell 7+)Default- codificação ANSI do sistema
Exemplo:
Get-Content -Path arquivo.txt -Encoding utf8Se você não souber a codificação, pode usar o cmdlet Format-Hex para inspecionar os bytes e identificar. Por exemplo:
Format-Hex -Path arquivo.txt | Select-Object -First 5Isso mostra os primeiros bytes. Se começar com EF BB BF, é UTF-8 com BOM; se começar com FF FE, é UTF-16 LE; e assim por diante.
No PowerShell 7, o padrão é UTF-8 sem BOM, o que é uma mudança em relação ao Windows PowerShell 5.1 que usava ANSI. Isso pode causar problemas ao ler arquivos criados com codificação ANSI. Se você estiver trabalhando com arquivos legados, especifique -Encoding Default ou -Encoding Ansi (equivalente).
Para escrever arquivos com uma codificação específica, use Set-Content com o parâmetro -Encoding.
Uma boa prática é sempre especificar a codificação ao ler e escrever, especialmente em scripts que serão executados em diferentes ambientes. Isso evita surpresas com caracteres especiais, como acentos.
Boas práticas e observações finais
Ao trabalhar com leitura de arquivos, considere as seguintes boas práticas:
- Sempre especifique a codificação ao ler e escrever arquivos, para garantir consistência.
- Para arquivos grandes, evite carregar todo o conteúdo na memória; use pipeline ou
-ReadCount. - Use
-Rawquando precisar do conteúdo como uma única string, especialmente para substituições globais. - Verifique se o arquivo existe antes de tentar lê-lo, usando
Test-Path, para evitar erros. - Considere usar
Get-Contentcom-Tailpara ler as últimas linhas de um arquivo, útil para logs.
Por exemplo, para ver as últimas 10 linhas de um log:
Get-Content -Path C:\logs\app.log -Tail 10E para monitorar um log em tempo real, use -Wait (disponível no Windows PowerShell e PowerShell 7):
Get-Content -Path C:\logs\app.log -Tail 5 -WaitIsso é útil para acompanhar logs enquanto o sistema grava.
Referências
- Documentação oficial do Get-Content
- Sobre codificação de caracteres no PowerShell
- Lendo e escrevendo arquivos de texto no PowerShell
- Método File.ReadLines no .NET
- Documentação do Set-Content
- Documentação do Format-Hex
Exercícios
Crie um script que leia um arquivo chamado
dados.txte exiba o número total de linhas.✓ Resposta:$linhas = Get-Content -Path dados.txt Write-Host "Total de linhas: $($linhas.Count)"Leia um arquivo usando
-Rawe exiba o comprimento da string resultante.✓ Resposta:$conteudo = Get-Content -Path dados.txt -Raw Write-Host "Comprimento: $($conteudo.Length)"Escreva um script que processe um arquivo linha a linha e imprima apenas as linhas que contêm a palavra "erro" (case-insensitive).
✓ Resposta:Get-Content -Path log.txt | ForEach-Object { if ($_ -match 'erro') { Write-Host $_ } }Leia um arquivo com codificação específica (por exemplo, UTF-8) e mostre as três primeiras linhas.
✓ Resposta:Get-Content -Path dados.txt -Encoding utf8 | Select-Object -First 3Use
-ReadCountpara ler um arquivo em blocos de 5 linhas e exibir o número de blocos lidos.✓ Resposta:$blocos = 0 Get-Content -Path dados.txt -ReadCount 5 | ForEach-Object { $blocos++ } Write-Host "Total de blocos: $blocos"