Este artigo dá sequência à discussão iniciada em OCaml handles, onde exploramos um pouco a ideia de processo e out_channel. Neste artigo, vamos explorar in_channel. Quando mudamos, é comum embalar nossos pertences em caixas; podemos embalar vários itens em uma caixa, o que torna fácil o transporte, imagine o trabalho que seria carregar uma pilha de itens. De modo análogo, na memória do computador, é preferível tratar itens em massa, assim podemos lidar com vários elementos de uma vez.
Anteriormente, fizemos uso do out_channel para escrever em um arquivo. Existe uma correspondência direta, permitindo-nos ler dados através de um canal de entrada, denominado in_channel. Vamos explorar como podemos ler de um arquivo. O primeiro passo é entender como abrir o canal de entrada:
Olhando a assinatura da função open_in, vemos que ela recebe uma string e retorna um in_channel. A função é implementada em termos de open_in_gen, que é uma função mais genérica que permite passar uma lista de open_flag. A flag Open_rdonly indica que o arquivo será aberto apenas para leitura, e Open_text indica que o arquivo será aberto em modo texto. O segundo argumento é um inteiro que representa a permissão do arquivo, que é ignorado quando o arquivo é aberto em modo leitura.
Depois de abrir o canal, o próximo passo é ler dele. Para ler um arquivo, temos a função input_value:
Como vemos na assinatura, ela recebe um in_channel e retorna uma a'. Combinando ambos, podemos ler arquivos:
Assim como fechávamos o out_channel com close_out, fechamos o in_channel com close_in.
Arquivos Gigantes
O exemplo anterior carrega todo o arquivo na memória, mas e se o arquivo for muito grande? Provavelmente não teremos memória suficiente para carregar todo o arquivo. Para lidar com arquivos grandes, podemos ler o arquivo em pedaços, uma das maneiras de fazer isso é usando input_line:
Como vemos na assinatura, ele recebe um in_channel e retorna uma string. A função lê uma linha do canal de entrada e retorna a linha lida sem o caractere de nova linha. Se o fim do arquivo for atingido, a função retorna exception End_of_file. Assim, podemos ler um arquivo linha por linha:
Outra maneira de ler arquivos em pedaços é usando input:
Na assinatura, temos que ele recebe um in_channel, um bytes que é o buffer onde os dados lidos serão armazenados, um inteiro que é o deslocamento no buffer onde os dados lidos serão armazenados, um inteiro que é o número de bytes a serem lidos e retorna um inteiro que é o número de bytes lidos. A função lê até n bytes do canal de entrada e os armazena no buffer a partir do deslocamento. Se o fim do arquivo for atingido, a função retorna 0. Assim, podemos ler um arquivo em chunks:
OCaml suporta a leitura de grandes arquivos. Normalmente, o tamanho máximo de arquivo é o tamanho do max_int, que na maioria dos sistemas é inferior a 2 GB. O módulo LargeFile oferece funções que retornam tamanho e posição, e também podem buscar nesses arquivos maiores. A utilização desse módulo fica como exercício para o leitor (😝).