SQLShack

Temos alguns ficheiros personalizados que recebemos de diferentes fornecedores e para estas situações não podemos utilizar programas ETL padrão sem qualquer personalização. Uma vez que estamos a expandir a nossa capacidade de ler estes ficheiros personalizados com .NET, estamos à procura de formas eficientes de ler ficheiros com PowerShell que podemos utilizar em SQL Server Job Agents, Windows Task Schedulers, ou com o nosso programa personalizado, que pode executar scripts PowerShell. Temos muitas ferramentas para analisar dados e queremos saber formas eficientes de ler os dados para análise, juntamente com a obtenção de linhas específicas de dados de ficheiros por número, ou pela primeira ou última linha do ficheiro. Para a leitura eficiente de ficheiros, quais são algumas funções ou bibliotecas que podemos utilizar?

Overview

Para a leitura de dados de ficheiros, queremos geralmente concentrar-nos em três funções principais para completar estas tarefas juntamente com alguns exemplos listados ao lado destas na prática:

  1. Como ler um ficheiro inteiro, parte de um ficheiro ou saltar num ficheiro. Podemos enfrentar uma situação em que queremos ler todas as linhas excepto a primeira e a última.
  2. Como ler um ficheiro utilizando poucos recursos do sistema. Podemos ter um ficheiro de 100GB que só queremos ler 108KB de dados.
  3. Como ler um ficheiro de uma forma que nos permita analisar facilmente os dados de que precisamos ou que nos permita utilizar funções ou ferramentas que utilizamos com outros dados. Uma vez que muitos programadores têm ferramentas de análise de strings, mover dados para um formato de string – se possível – permite-nos reutilizar muitas ferramentas de análise de strings.

O acima descrito aplica-se à maioria das situações envolvidas com a análise de dados de ficheiros. Começaremos por olhar para uma função PowerShell incorporada para a leitura de dados, depois veremos uma forma personalizada de ler dados de ficheiros usando PowerShell.

Função Get-Content da PowerShell

A última versão da PowerShell (versão 5) e muitas versões anteriores da PowerShell vêm com a função Get-Content e esta função permite-nos ler rapidamente os dados de um ficheiro. No guião abaixo, produzimos os dados de um ficheiro inteiro no ecrã do PowerShell ISE – um ecrã que iremos utilizar para fins de demonstração ao longo deste artigo:

1
Get-Conteúdo “C:\Registo de registos.txt”

/td>

>p>div>

Get-O conteúdo produz o ficheiro completo de registo.txt para o ecrã do PowerShell ISE (note que a imagem acima é apenas parte do ficheiro completo).

Podemos guardar toda esta quantidade de dados numa cadeia, chamada os nossos arquivosdados:

1
2

$ourfilesdata = Get-Conteúdo “C:\registo de registos.txt”
$ourfilesdata

Obtemos o mesmo resultado que o anterior, a única diferença aqui é que salvámos o ficheiro inteiro numa variável. No entanto, enfrentamos uma desvantagem, se guardarmos um ficheiro inteiro numa variável ou se emitirmos um ficheiro inteiro: se o tamanho do ficheiro for grande, teremos lido o ficheiro inteiro numa variável ou emitido o ficheiro inteiro no ecrã. Isto começa a custar-nos desempenho, pois lidamos com ficheiros de maior tamanho.

Podemos seleccionar uma parte do ficheiro tratando a nossa variável (sendo o objecto outro nome) como uma consulta SQL onde seleccionamos alguns dos ficheiros em vez de todos eles. No código abaixo, seleccionamos as primeiras cinco linhas do ficheiro, em vez do ficheiro inteiro:

1
2

$ourfilesdata = Get-Conteúdo “C:\registo de registos.txt”
$ourfilesdata | Select-Object -Primeiro 5

p>

A janela de saída do PowerShell ISE retorna apenas as primeiras cinco linhas do ficheiro.

Também podemos usar a mesma função para obter as últimas cinco linhas do ficheiro, usando uma sintaxe semelhante:

1
2

$ourfilesdata = Get-Content “C:\registo de registos.txt”
$ourfilesdata | Select-Object -Últimos 5

>p>

A janela de saída do PowerShell ISE apenas devolve as últimas cinco linhas do ficheiro.

A função Get-Content integrada no PowerShell pode ser útil, mas se quisermos armazenar muito poucos dados em cada leitura por razões de análise, ou se quisermos ler linha a linha para analisar um ficheiro, podemos querer usar a classe StreamReader de .NET, o que nos permitirá personalizar a nossa utilização para aumentar a eficiência. Isto faz de Get-Content um grande leitor básico para dados de ficheiros.

A biblioteca StreamReader

Numa nova janela do PowerShell ISE, vamos criar um objecto StreamReader e dispor deste mesmo objecto executando o código PowerShell abaixo:

1
2
3

$newstreamreader = New-Sistema de Objectos.IO.StreamReader(“C:\logging\logging.txt”)
#### Leitura de ficheiros aqui
$newstreamreader.Eliminar()

Em geral, sempre que criamos um novo objecto, é uma boa prática remover esse objecto, uma vez que liberta recursos informáticos sobre esse objecto. Embora seja verdade que .NET fará isto automaticamente, ainda assim recomendo que o faça manualmente, pois pode trabalhar com línguas que não o façam automaticamente no futuro e é uma boa prática.

Nada acontece quando executamos o código acima porque não chamámos nenhum método – apenas criámos um objecto e removemo-lo. O primeiro método que vamos analisar é o método ReadToEnd():

1
2
3

$newstreamreader = New-Sistema de Objectos.IO.StreamReader(“C:\logging\logging.txt”)
$newstreamreader.ReadToEnd()
$newstreamreader.Eliminar()

p>

O método ReadToEnd() para StreamReader parece idêntico ao Get-Conteúdo na janela do ISE na medida em que produz todos os dados do ficheiro.

Como vemos na saída, podemos ler todos os dados do ficheiro como com Get-Content usando o método ReadToEnd(); como lemos cada linha de dados? Incluído na classe StreamReader está o método ReadLine() e se o chamássemos em vez de ReadToEnd(), obteríamos a primeira linha dos dados dos nossos ficheiros:

1
2
3

$newstreamreader = New-Sistema de Objectos.IO.StreamReader(“C:\logging\logging.txt”)
$newstreamreader.ReadLine()
$newstreamreader.Eliminar()

p>

O método ReadLine() lê a linha actual do ficheiro, que, neste caso, é a primeira linha.

Uma vez que dissemos ao StreamReader para ler a linha, ele leu a primeira linha do ficheiro e parou. A razão para isto é que o método ReadLine() só lê a linha actual (neste caso, a linha um). Temos de continuar a ler o ficheiro até chegarmos ao fim do ficheiro. Como é que sabemos quando um ficheiro termina? A linha final é nula. Por outras palavras, queremos que o StreamReader continue a ler o ficheiro (enquanto o laço) desde que cada nova linha não seja nula (por outras palavras, tenha dados). Para demonstrar isto, vamos adicionar um contador de linhas a cada linha sobre a qual iteramos, para que possamos ver a lógica com números e texto:

1
2
3
4
5
6
7
8

$newstreamreader = New-Sistema de Objectos.IO.StreamReader(“C:\logging\logging.txt”)
$eachlinenumber = 1
while (($readeachline =$newstreamreader.ReadLine()) -ne $null)
{
Write-Host “$eachlinenumber $readeachline”
$eachlinenumber++
}
$newstreamreader.Eliminar()

p>

O nosso contador apresenta agora cada linha juntamente com a linha do texto do ficheiro.

À medida que o StreamReader lê cada linha, armazena os dados da linha no objecto que criámos $readeachline. Podemos aplicar funções de string a esta linha de dados em cada passagem, tais como obter os primeiros dez caracteres da linha de dados:

1
2
3
4
5
6
7

$newstreamreader = Novo-Sistema de Objectos.IO.StreamReader(“C:\logging\logging.txt”)
$eachlinenumber = 1
while (($readeachline = $newstreamreader.ReadLine()) -ne $null)
{
$readeachline.Substring(0,10)
}
$newstreamreader.Eliminar()

p>

StreamReader devolve os primeiros dez caracteres de cada linha de dados, utilizando o método de string Substring.

Podemos estender este exemplo e chamar dois outros métodos de string – desta vez incluindo os métodos de string IndexOf e Replace(). Apenas chamamos estes métodos nas duas primeiras linhas, obtendo apenas as linhas menos do que a linha três:

>>

$newstreamreader = New-Sistema de Objectos.IO.StreamReader(“C:\logging\logging.txt”)
$eachlinenumber = 1
while (($readeachline = $newstreamreader.ReadLine()) -ne $null)
{
if ($eachlinenumber -lt 3)
{
Write-Host “$eachlinenumber”
$readeachline.Substring(0,12)
$readeachline.IndexOf(” “)
$readeachline.Replace(” “, “replace”)
}
$eachlinenumber++
}
$newstreamreader.Eliminar()

1
2
3
4
5
6
7
8
9
10
11
12
13
14

p>

The Substring(), IndexOf() e Replace() nas duas primeiras linhas do ficheiro.

Para analisar os dados, podemos usar os nossos métodos de string em cada linha do ficheiro – ou numa linha específica do ficheiro – em cada iteração do laço.

Finalmente, queremos ser capazes de obter uma linha específica do ficheiro – podemos obter a primeira e última linha do ficheiro usando Get-Content. Vamos usar o StreamReader para apostar um número de linha específico que passamos para uma função personalizada que criamos. Vamos criar uma função reutilizável que devolve um número de linha específica, a seguir queremos embrulhar a nossa função para reutilização enquanto exigimos duas entradas: a localização do ficheiro e o número de linha específica que queremos devolver.

Função Get-FileData {
Param(
$ourfilelocation
, $specificline
)
Processo
{
$newstreamreader = Sistema Novo-Objecto.IO.StreamReader($ourfilelocation)
$eachlinenumber = 1
while (($readeachline = $newstreamreader.ReadLine()) -ne $null)
{
if ($eachlinenumber -eq $specificline)
{
$readeachline
break;
}
$eachlinenumber++
}
$newstreamreader.Dispose()
}
}
$savelinetovariable = Get-FileData -ourfilelocation “C:\logging\loggingtxt” -specificline 17
$savelinetovariable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

/div>

Se verificarmos, A linha 17 retorna “A extensão da piscina tampão já está desactivada. Nenhuma acção é necessária” correctamente. Além disso, quebramos a declaração se – uma vez que não há necessidade de continuar a ler o ficheiro uma vez obtida a linha de dados que queremos. Além disso, o método de disposição termina o objecto, pois podemos verificar chamando o método a partir da linha de comando no PowerShell ISE e ele não retornará nada (também podemos verificar dentro da função e obter o mesmo resultado):

P>P> Para um desempenho personalizado, o StreamReader oferece mais potencial, uma vez que podemos ler cada linha de dados e aplicar as nossas funções adicionais de acordo com as nossas necessidades. Mas nem sempre precisamos de algo para personalizar e podemos querer apenas ler algumas primeiras e últimas linhas de dados, caso em que a função Get-Content adequa-se bem a nós. Além disso, os ficheiros mais pequenos funcionam bem com Get-Content, uma vez que nunca estamos a receber demasiados dados de cada vez. Basta ter cuidado se os ficheiros tendem a crescer com o tempo.

  • Autor
  • Posts recentes
Timothy Smith
Tim gere centenas de instâncias do SQL Server e MongoDB, e concentra-se principalmente na concepção da arquitectura apropriada para o modelo de negócio.
Passou uma década a trabalhar em FinTech, juntamente com alguns anos em BioTech e Energy Tech. Acolhe o West Texas SQL Server Users’ Group, bem como ensina cursos e escreve artigos sobre SQL Server, ETL, e PowerShell.
No seu tempo livre, é um contribuinte da indústria financeira descentralizada.
Veja todos os posts de Timothy Smith

Timothy Smith
Latest posts de Timothy Smith (ver todos)
  • Máscara de Dados ou Alteração de Informação Comportamental – 26 de Junho, 2020
  • Teste de segurança com gamas extremas de volume de dados – 19 de Junho de 2020
  • Afinação do desempenho do SQL Server – RESOURCE_SEMAPHORE espera – 16 de Junho de 2020
  • Deixe uma resposta

    O seu endereço de email não será publicado. Campos obrigatórios marcados com *