ROMARIO escreveu:fiquei curioso em saber como você faz os teus sistemas
Com relação à indicação dos diretórios, é como eu disse: não uso e pronto. Você pode fazer assim também. Apenas esqueça a existência de coisas como SET DEFAULT e explicite os nomes dos diretórios, junto aos nomes dos arquivos que deverão ser abertos. Só isso.
Agora, com relação ao fato de eu não usar o comando USE, a explicação é mais longa. Já há muitos anos, percebendo as dificuldades de utilização do sistema tradicional de abertura, criei o conceito de grupos de arquivos de dados. Primeiro, veja as dificuldades. Imagine que você precisa abrir 10 arquivos de dados e seus índices. Dentro deste grupo de 10 arquivos, 5 são essenciais, 4 são opcionais (se não for possível abrir, não haverá problema) e 1 é temporário e deverá estar "zerado". Pelo método tradicional, imagine se a abertura do oitavo arquivo falhar. Todos os sete arquivos anteriores terão de ser fechados. Se você der um dbCloseAll(), resolve, mas isso fechará todos, inclusive os arquivos abertos em funções anterior à esta, que precisam continuar aberto. Assim, será melhor fechar um a um. Serão muitos e muitos IFs. Tudo bem que o programador é um profissional que deve se acostumar ao trabalho pesado, mas assim é um desperdício enorme de produtividade.
Então, resolvi montar um sub-sistema de manutenção de arquivos de dados, que deveria me livrar desse tipo de pesadelo.
Ele funciona de maneira bem simples. Cada arquivo de dados tem sua geometria (dados dos arquivos (DBF e índices) e campos) definida em uma função nomeada de forma padronizada. Algo do tipo:
Código: Selecionar todos
DatCadfun() --> Cadastro de funcionários
DatDocEnt() --> Documentos fiscais de entrada
DatDocSai() --> Documentos fiscais de saída
DatProFis() --> Processamento dos dados fiscais
Veja como é uma das minhas funções de geometria mais simples:
Código: Selecionar todos
function DatCtaRec(nOut)
local cAlias := "CtaRec"
local cID := SigEmpSel(cAlias)
dbServReq(nOut)
defDBF as "CTAREC."+cID at EmpDatDir(cID) alias cAlias comment "Contas a Receber"
defIDX at EmpIdxDir(cID)
defKey "CODIGO" alias "iCTR_CODIGO"
defKey "CONJUNTO+NUMERO" alias "iCTR_CNJNRO"
defKey "NUMERO" alias "iCTR_NRO"
defKey "DTOS(VENCIMENTO)+NUMERO" alias "iCTR_VNCNRO"
defKey "DTOS(PAGAMENTO)+NUMERO" alias "iCTR_PAGNRO"
defKey "DTOS(PAGAMENTO)+DTOS(VENCIMENTO)+NUMERO" alias "iCTR_PAGVNCNRO"
defKey "CLIENTE+NUMERO" alias "iCTR_CLINRO"
defKey "CLIENTE+DTOS(VENCIMENTO)+NUMERO" alias "iCTR_CLIVNCNRO"
*
defStruct
defFld "CODIGO" cha 6 // código de identificação no sistema
defFld "CONJUNTO" cha 6 // conjunto do qual esta conta faz parte
defFld "CLIENTE" cha 6 // código do cliente
//
defFld "NUMERO" cha 9 // número do documento
defFld "DATAEMISS" dat // data de emissão da duplicata
defFld "VENCIMENTO" dat // data do vencimento
defFld "PAGAMENTO" dat // data do pagamento
defFld "VALOR" num 9,2 // valor total
defFld "DESCONTO" num 9,2 // valor do desconto concedido
defFld "ACRESCIMO" num 9,2 // valor do acréscimo cobrado
//
defFld "DPLSPEND" log // se verdadeiro, vínculo vazio
defFld "DOCORIGEM" num 1 // documento de origem: 1=DocSai 2=DocSer
defFld "CODORIGEM" cha 6 // código deste documento de origem
//
defFld "LSTUPDINFO" cha 31 // última alteração
defFld "VER001_CRC" cha 8 // versão da estrutura e CRC32 do registro
*
return dbCloseReq()
Qualquer manipulação em arquivos de dados representa a invocação de um código de serviço. A abertura chamará esta função (por macro-substituição) com um código próprio. A função dbServReq() na quarta linha inicia o serviço e a função dbCloseReq() informa que o serviço foi completado. Com o código apropriado, uma função do sub-sistema vai recebendo o conteúdo de cada comando listado acima e, de acordo com o código de serviço, "filtrará" o que for necessário, descartando o resto. Se, por exemplo, na abertura o arquivo não for encontrado e houver um comando de criação, esta função será novamente chamada, com o código de requisição de estrutura. Aquela função do sistema, percebendo o código diferente, "filtrará" as informações acima, acumulando em matriz apenas as informações a respeito da estrutura do arquivo.
Aliás, note que na quinta linha eu defino o diretório onde reside (ou será criado) o arquivo. É a parte
at EmpDatDir().
Essa é a descrição sucinta de como é a base dos dados dos arquivos, que me fornecem apenas informações.
Fiz esse sub-sistema para que eu não tivesse mais que ficar repetindo o trabalho enfadonho de ter que ficar testando a abertura de cada arquivo de dados e índices. Assim, com uma série de comandos criados especialmente, o exemplo que dei sobre os 10 arquivos DBF ficariam, no meu sub-sistema, assim:
Código: Selecionar todos
dbDefGroup Arq_01 create vital exclusive reindexIF .T.
dbDefGroup Arq_02 reindexIF TstReindex()
dbDefGroup Arq_03 create vital reindexIF .T.
dbDefGroup Arq_04 exclusive reindexIF TstReindex()
dbDefGroup Arq_05 create vital exclusive
dbDefGroup Arq_06 create vital
dbDefGroup Arq_07 create vital exclusive reindexIF .T.
dbDefGroup Arq_08 exclusive
dbDefGroup Arq_09 create vital reindexIF .T.
dbDefGroup TmpExp create kill vital
*
if !dbOpenGrp("MyGroup")
// Se o retorno foi FALSE, significa que nem todos os arquivos com
// a cláusula vital puderam ser abertos. Assim sendo, fim!
//
return nil
end
Muito mais fácil. Sem os comentários, são apenas 13 linhas de código bem legível e fácil de manter, que abrirão os arquivos que puderem ser abertos, criarão esses DBFs se não existirem, criarão todas as chaves de índices (eu uso a LIB SIX) e reindexarão, se for necessário ou possível (neste exemplo, em alguns arquivos a reindexação dependerá do retorno da função TstReindex()). E ainda por cima, apagará fisicamente o arquivo temporário (cláusula KILL) no fechamento do grupo. Eu não exemplifiquei todos os recursos. Há outras cláusulas e funções de apoio.
Agora, tente fazer isso tudo usando o método tradicional. A quantidade de código será muito maior. Isso num único ponto do programa. Imagine num sistema com dezenas de aberturas como essa.
Mas, além da facilidade demonstrada acima, há algumas características interessantes. Através desse sistema de grupos, posso, por exemplo, abrir o mesmo DBF 2 ou mais vezes, ao mesmo tempo. Explico: depois que o grupo é "cadastrado" pelos comandos acima, a função dbOpenGrp() tentará abrir os arquivos um a um. Antes de tentar abrir um arquivo, ela verificará se em seu repositório de controle já existe, num grupo aberto anteriormente, um DBF com a mesma identificação (alias). Se não existir, o processo de abertura prossegue normalmente. Se existir, uma nova instância de controle é criada, e todas as características de posicionamento e filtragem são armazenadas. Assim, quando esse grupo for fechado, tais características (SCOPE, FILTER, RecNo()) serão restauradas para que fiquem exatamente como estavam antes da abertura do grupo. No limite da possibilidade, claro.
O sistema é mais extenso que isso, mas acho que você já deve ter tido uma boa noção do porquê eu não uso mais o velho USE. Com um sistema desses, não preciso mais dele, felizmente.
[]'s
Maligno
http://www.buzinello.com/prg