Mostrando postagens com marcador Arquivos. Mostrar todas as postagens
Mostrando postagens com marcador Arquivos. Mostrar todas as postagens

quinta-feira, 31 de janeiro de 2008

O segredo do External File Handler

Aprendendo sobre alguns recursos do compilador Microfocus, é possível acessar bancos de dados sem mexer numa única linha de código dos seus programas que acessam arquivos indexados. Sim, isso é possível. Continue usando "read", "start", "open", mas tenha em suas mãos o banco de dados de sua preferência.

Esse artigo foi escrito baseado na versão 3.0 e 3.1 do NetExpress.

Conhecendo o External File Handler
Quando escrevemos em nossos programas comandos de acesso a um arquivo, um "open", um "read" ou um "start", o compilador converte esses comandos em chamadas para o executável EXTFH.EXE. Esse é o executável do runtime que realiza todas as operações de arquivos no compilador Microfocus. As chamadas são feitas exatamente como no código a seguir:

call "EXTFH" using Operacao DadosDoArquivo

Um código específico é enviado ao EXTFH quando efetuamos, por exemplo, um "open" em um arquivo. Além do código específico da operação, os dados do arquivo são passados através de uma estrutura de dados, que se encontra no arquivo XFHFCD.CPY, um "copybook file" que pode ser copiado em qualquer fonte Cobol. Esse arquivo encontra-se na pasta SOURCE, dentro da pasta de instalação do NetExpress.

A estrutura de dados XFHFCD.CPY
No arquivo de ajuda do Microfocus NetExpress não existem muitas informações sobre a estrutura de dados encontrada no arquivo XFHFCD.CPY, infelizmente. Porém, com um pouco de paciência, o desenvolvedor vai encontrar a descrição de alguns dos campos dessa estrutura, além da relação completa dos códigos que identificam as operações de arquivos passadas para o EXTFH.

Criando seu próprio External File Handler
O compilador Microfocus permite que o desenvolvedor crie seu próprio External File Handler. Assim, todas as chamadas das operações de arquivos serão feitas para esse programa. Com esse recurso, o desenvolvedor pode "interceptar" as operações de um determinado arquivo e intepretá-las da forma que desejar. A diretiva CALLFH indica qual programa deve ser chamado para interpretar as operações de arquivo:

$SET CALLFH"MEUFH"

Com essa diretiva definida em um programa, todas as operações de arquivos nesse programa serão convertidas para o código a seguir:

call "MEUFH" using Operacao DadosDoArquivo

O programa MEUFH.CBL
No exemplo a seguir, o programa MEUFH.CBL recebe os dados do programa chamador e simplesmente faz a chamada para o EXTFH, que é o External File Handler padrão da Microfocus, sem fazer qualquer alteração nas operações de arquivos:

program-id. MEUFH.

linkage section.
01 lnkOperacao pic xx.
01 lnkDadosDoArquivo.
copy "XFHFCD.CPY".

procedure division using lnkOperacao lnkDadosDoArquivo.

....call "EXTFH" using lnkOperacao lnkDadosDoArquivo
....exit program.

Obtendo outras informações do arquivo
Adicionando algumas linhas, poderíamos obter outras informações do arquivo:

program-id. MEUFH.

working-storage section.
77 wsTamanhoDoRegistro pic 9(09) comp-5.

linkage section.
01 lnkOperacao pic xx.
01 lnkDadosDoArquivo.
copy "XFHFCD.CPY".

01 lnkNomeDoArquivo pic x(1024).
01 lnkRegistro pic x(32767).

procedure division using lnkOperacao lnkDadosDoArquivo.
....*> Para saber o nome do arquivo
....set address of lnkNomeDoArquivo to fcd-filename-address

....*> Para saber o tamanho do registro
....move fcd-current-rec-len to wsTamanhoDoRegistro

....*> Para pegar o conteúdo do registro que foi passado
....set address of lnkRegistro to fcd-record-address

....call "EXTFH" using lnkOperacao lnkDadosDoArquivo
....exit program.

Acessando tabelas de um banco de dados
Com as informações básicas descritas acima, o desenvolvedor poderia identificar qual operação foi requisitada e em qual arquivo essa operação seria efetuada. Identificada a operação, bastaria efetuar no mesmo programa MEUFH.CBL, chamadas a parágrafos ou rotinas que processariam a operação específica, porém, utilizando a tabela correspondente em um banco de dados. utilizando e atualizando a variável que corresponde ao registro do arquivo, ao retornar para o programa chamador, todos os dados estariam devidamente atualizados, sem a necessidade real de qualquer alteração no programa que contém os comandos "open", "read" ou "start".

Exemplos práticos
Aos desenvolvedores que pesquisarem sobre esse assunto e conseguirem resultados práticos, sintam-se à vontade para enviarem seus materiais, projetos e programas, para que eu possa publicá-los e assim ajudar a outros desenvolvedores que desejam utilizar os mesmos recursos. Compartilhando a informação, teremos sempre o melhor do que a linguagem pode nos oferecer. Estarei sempre contando com a colaboração de vocês.

quarta-feira, 22 de agosto de 2007

Eu coleciono registros. E você ?

Você coleciona tampinhas, latinhas de alumínio, selos ou carrinhos em miniatura ? Aprenda a criar coleções de registros dos seus arquivos indexados e comece a pensar mais em objetos:

Na class-control, defina as classes que serão utilizadas:

class-control.
....CharacterArray is class "chararry"
....OrderedCollection is class "ordrdcll".

Vamos tomar como exemplo um registro de um arquivo de bancos, com código e nome do banco. Mas você pode adaptar esse exemplo com qualquer outra FD:

FD CadastroDeBancos.
01 RegistroDoBanco.
...02 CodigoDoBanco pic 9(03).
...02 NomeDoBanco pic x(60).

Na working-storage section, defina as seguintes variáveis:

77 umaColecao object reference value null.
77 umObjeto object reference value null.
77 wsTamanho pic 9(09) comp-5 value zeros.
77 wsQuantidade pic 9(09) comp-5 value zeros.
77 wsPosicao pic 9(09) comp-5 value zeros.

A primeira coisa a ser feita é criar uma coleção para armazenar todos os objetos contendo os registros lidos. Essa coleção é criada a partir do método "OfReferences" da classe OrderedCollection:

move 0 to wsQuantidade
invoke OrderedCollection "ofReferences" using wsQuantidade
returning umaColecao

Agora, digamos que exista um procedimento em seu programa que leia o arquivo de bancos, registro a registro, através de um "read ArquivoDeBancos next". A cada registro lido, você pode criar então um objeto do tipo CharacterArray, através do método "WithLengthValue". Esse método recebe como parâmetros, o tamanho e o conteúdo do objeto que se deseja criar. Em nosso exemplo, vamos passar o tamanho do registro de bancos e o seu conteúdo:

move length of RegistroDoBanco to wsTamanho
invoke CharacterArray "withLengthValue"
using wsTamanho RegistroDoBanco returning umObjeto

Em seguida, armazenamos o objeto criado utilizando o método "Add". Esse método armazena os objetos na coleção, na mesma ordem em que são adicionados: o primeiro fica na primeira posição da coleção, o segundo na segunda posição, e assim por diante:

invoke umaColecao "add" using umObjeto

Isso deve ser feito a cada registro lido do arquivo. Ao terminar a leitura do arquivo, você terá o objeto umaColecao contendo diversos objetos, cada um deles com o conteúdo de um registro lido do arquivo de bancos. Uma aplicação prática para a utilização desse recurso seria criar rotinas que gerem essas coleções baseadas em determinados critérios. Em uma rotina que manipulasse um arquivo de empresas poderiam ser criadas coleções de empresas de um determinado tipo: pessoa jurídica, por exemplo. Em uma rotina que manipulasse um arquivo de funcionários poderiam ser criadas coleções com funcionários ativos, outra com funcionários desligados.

Quando um programa recebe uma coleção de objetos, ele pode saber a quantidade de objetos na coleção através do método "size":

invoke umaColecao "size" returning wsQuantidade

Se você deseja pegar um objeto em uma posição específica dentro da coleção, pode se utilizar o método "at":

move 5 to wsPosicao
invoke umaColecao "at" using wsPosicao
returning umObjeto


No exemplo acima, recuperamos o objeto na quinta posição da coleção. Note que se a coleção não contém o objeto na posição especificada, uma mensagem de erro será retornada. Se a coleção contém 5 objetos, você não pode tentar recuperar um objeto na posição 9, por exemplo.

Depois de recuperado um objeto, você pode retornar seu conteúdo novamente em uma variável. Em nosso exemplo, vamos recuperar o conteúdo diretamente no registro de bancos. Para retornar o conteúdo de um objeto, utilize o método "getValue":

invoke umObjeto "getValue" returning RegistroDoBanco

Atente para um detalhe: a variável que receberá o conteúdo de um objeto deve ter tamanho suficiente para armazenar a informação. Caso o tamanho não seja suficiente, você pode ter problemas de violação de memória.

Agora é só usar a criatividade e criar as suas próprias coleções de registros.

quarta-feira, 25 de julho de 2007

Criando um "record layout"

O IDE do NetExpress oferece alguns recursos na manipulação de arquivos nativos. Um deles é a criação de um "record layout" para facilitar a leitura dos registros de um arquivo e a identificação de cada um de seus campos. Aprenda como criar um "record layout" utilizando a IDE do NetExpress:

Localize o fonte cobol que contém a FD do arquivo. Clique com o botão direito do mouse e selecione a opção "Create record layout":




Em seguida, na janela da esquerda você verá a DATA DIVISION e as FD´s dos arquivos que estiverem definidas no fonte cobol escolhido. Clique com o botão direito no ítem que corresponde ao registro que você deseja criar o "record layout" e selecione a opção "New record layout..."




A janela "New Record Layout Wizard" será aberta. Deixe selecionada a opção "Default layout" e clique em Avançar. A outra opção permite criar condições para a visualização dos registros e é apropriada para usuários mais avançados.




Em seguida, clique em Concluir.




Você verá na janela da direita do seu IDE, o "record layout" criado.




Basta agora salvar o "record layout" em um arquivo. Vá até o meu File e selecione a opção "Save as...". Escolha o nome e a pasta onde será salvo o arquivo com o "record layout". O arquivo terá a extensão "STR".




Agora vamos abrir o arquivo nativo para o qual criamos o "record layout". Selecione o menu "File" e vá em "Open...". Selecione a pasta e o arquivo.




Você verá na janela da esquerda, todos os registros do arquivo. E na janela da direita, os dados dos registros identificados campo a campo, de acordo com o "record layout" criado.




A partir daí, a visualização e a manipulação dos dados do arquivo podem ser feitas campo a campo.

Tenha cuidado ao manipular os dados do arquivo que estão dispostos no IDE, pois qualquer alteração irá refletir diretamente nos dados gravados no arquivo.

quarta-feira, 16 de maio de 2007

A quantidade de registros em um arquivo

Já existe desde março no site da Microfocus um exemplo de como detectar a quantidade de registros em um arquivo ISAM. O exemplo no site está documentado para ser utilizado com a versão 4.0 do NetExpress, mas já fiz testes com a versão 3.0 e 3.1 e funcionou perfeitamente.

O segredo é a utilização de alguns arquivos "cpy" que contém estruturas identificando os cabeçalhos dos arquivos indexados. São feitas chamadas ao "EXTFH.EXE" que retorna as informações sobre qualquer arquivo indexado nos dados dessas estruturas. Pode-se saber, por exemplo, o tipo de arquivo, a quantidade de chaves, o tamanho do registro, se são registros fixos ou variáveis, entre outras informações. Vale a pena dar uma conferida e utilizar esse recurso.