verificar integridade do dbf ???

Fórum sobre a linguagem CA-Clipper.

Moderador: Moderadores

Avatar do usuário
adilson
Usuário Nível 2
Usuário Nível 2
Mensagens: 93
Registrado em: 01 Fev 2008 07:02
Localização: americana - sao paulo

verificar integridade do dbf ???

Mensagem por adilson »

Amigos Boa Tarde !

E o Seguinte estou fazendo atualizaçoes via ftp entre filias de um cliente meu, na hora que eu puxar os arquivos
dbf gostaria de checar sua integridade para poder tomar uma decisao tipo :

se o arquivo esta ok ! atualiza
se nao ! pula ...

e que ja aconteceu de o arquivo vir com o nome correto exemplo : est001.dbf (tamanho = 0) e na hora de abrir
deus erro de corrupção .


se alguem puder dar um toque agradeço

Abraço a todos ...
Burroughs L3000 (4 kb ram) e B700,Labo 8034-8038 (Basic Nixdorf),Apple II plus,Clipper 5.2e e começando com xharbour 0.99.70
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: verificar integridade do dbf ???

Mensagem por Maligno »

Crie um protocolo onde, além de transferir os arquivos, transfira também o hash de cada um deles. Assim, ao chegarem no destino, basta recalcular o hash de cada arquivo e comparar com o hash enviado como texto.

Você pode escolher o hash que quiser utilizar. Se for CRC32 ou MD5 (os mais populares, creio), tenho no meu site. Para CRC32 (OBJ), clique aqui. Se for MD5 (LIB), clique aqui.
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Re: verificar integridade do dbf ???

Mensagem por alxsts »

Olá amigos!

Adilson, se optar por outra solução, tenho a rotina exibida abaixo. Ela verifica, entre outras coisas, se o DBF tem um arquivo MEMO e, neste caso, se ele está presente na mesma pasta do DBF.

Código: Selecionar todos

//--------------------------------------------------------------------------
//     Testar se o DBF a ser aberto ? v lido.
//
//        0 - Everything ok
//       -1 - File is corrupt
//       -2 - File does not exist
//       -3 - DBF file is set to read only
//       -4 - Memo file is missing
//       >0 - A DOS error
//        2 - File not found
//        3 - Path not found
//        4 - Too many files open
//        5 - Access denied
//        6 - Invalid handle
//        8 - Insufficient memory
//       15 - Invalid drive specified
//       19 - Attempted to write to a write-protected
//       21 - Drive not ready
//       23 - Data CRC error
//       29 - Write fault
//       30 - Read fault
//       32 - Sharing violation
//       33 - Lock Violation
//
//   Exemplo:  If ValidDBF( <xcFile>) != 0
//                Alert( <xcFile> +  " : " <cMessage> )
//             Endif
//
//--------------------------------------------------------------------------
Function ValidDbf( cFile )

   #define VALID_SIGNATURE_BYTES {   3, 131, 139, 245 }
   #define DBT_FILE_NEEDED_BYTES { 131, 139, 245      }
   #define MEMO_FILE_EXTENSIONS  { "DBT", "DPT", "FPT" }

   #include "FILEIO.CH"
   
   Local cDir    := Set(_SET_DEFAULT)
   Local nHandle := FOpen( cDir + cFile + If( At( ".", Upper( cFile ) ) > 0, "", ".DBF" ), 66 )
   Local cBuf    := Space( 12 )
   Local nSign   := 0
   Local nReturn := 0
   Local nBlocks := 0
   Local nSize   := 0
   Local nRecs   := 0
   Local nRecSize:= 0
   Local nOffset := 0
   Local x

   If nHandle != -1
      FRead( nHandle, @cBuf, 12 )
      nSize := FSeek(nHandle, 0, FS_END )
      FClose( nHandle )
      nSign := Asc( cBuf )
      If Ascan( VALID_SIGNATURE_BYTES, nSign ) > 0

         nRecs    := Bin2l( Subs( cBuf,  5, 4 ) )
         nRecSize := Bin2w( Subs( cBuf, 11, 2 ) )
         nOffset  := Bin2w( Subs( cBuf,  9, 2 ) )

         If nRecs > 0
            nReturn := If( Abs( ( nRecs * nRecSize ) + nOffset - nSize ) < 3, 0, -1 )
         Else
            nReturn := If( nOffset <= nSize + 1, 0, -1 )
         Endif
      Else
         nReturn := -1
      Endif

      If nReturn == 0
         If ( x := Ascan( DBT_FILE_NEEDED_BYTES, nSign ) ) > 0
            nReturn := -4
            nHandle := FOpen( cdir + cFile + "." + MEMO_FILE_EXTENSIONS[ x ], 64 )
            If nHandle != -1
               If MEMO_FILE_EXTENSIONS[ x ] == "DBT"
                  cBuf    := Space( 4 )
                  FRead( nHandle, @cBuf, 4 )
                  nSize   := FSeek( nHandle, 0, FS_END )
                  nBlocks := Bin2l( cBuf ) * 512
                  If nSize <= ( nBlocks + 1 ) .and. nSize > ( nBlocks - 512 )
                     nReturn := 0
                  Endif
                  FClose( nHandle )
               Else
                  nReturn := 0
               Endif
            ElseIf FError() == 2
               nReturn := -2
            Endif
         Endif
      Endif
   Else
      If Ferror() == 5
         nReturn := -3
      Else
         nReturn := Ferror()
      Endif
   Endif
Return nReturn
//------------------------------------------------------------------------------
[]´s
AlxSts
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
adilson
Usuário Nível 2
Usuário Nível 2
Mensagens: 93
Registrado em: 01 Fev 2008 07:02
Localização: americana - sao paulo

Re: verificar integridade do dbf ???(resolvido)

Mensagem por adilson »

Ola Amigos ! bom dia !
No meu caso quando o comando put do ftp baixa o arquivo e as vezes o mesmo vinha com tamanho
zero fiz da seguinte forma e deu certo !

#include "directry.ch"
arq="esto01.dbf" // arquivo baixado via ftp
comoe:=directory("&arq","D")
if comoe[1,2]=0 // indica o tamanho do arquivo
// pula tratamento // no caso corrompido
endif
// segue tratamento normal

obrigado ao Maligno e alxsts pela força tb

[]´s
Burroughs L3000 (4 kb ram) e B700,Labo 8034-8038 (Basic Nixdorf),Apple II plus,Clipper 5.2e e começando com xharbour 0.99.70
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Re: verificar integridade do dbf ???

Mensagem por alxsts »

Olá Adilson.

Da forma como voce fez, está apenas ignorando arquivos vazios. Se houver outro problema no arquivo, passará despercebido.

[]´s
AlxSts
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

verificar integridade do dbf ???

Mensagem por Pablo César »

É isso mesmo, eu fosse você adicionaria um else (caso contrário que o arquivo seja igual a zero) e chamaria essa função que o colega postou. Além disso, tenha o cuidado de tranbsmitir via ftp como binary, aconteceu um caso similar recentemente em que os arquivos vinham fragmentados, veja este tópico:

viewtopic.php?f=39&t=9498&start=0&st=0&sk=t&sd=a
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
TerraSoftware
Usuário Nível 3
Usuário Nível 3
Mensagens: 353
Registrado em: 28 Jul 2004 13:14
Localização: Cianorte-PR
Contato:

Re: verificar integridade do dbf ???

Mensagem por TerraSoftware »

Caros colegas, achei este assunto muito interessante.
Baixei a funcao postada, testei e funcionou muito bem. Embora que ela nao me avisa que um determinado arquivo tem alguns linhas corrompidas.
Claro que entendo que isso ela nao pode fazer mesmo, visto que testa apenas a abertura do arquivo.
Entao, aproveitando o assunto, pergunto: existe alguma forma de abrir um dbf e testar todo o conteudo do mesmo? ou seja, vasculhar o arquivo por linhas corrompida?
www.sisterra.com.br
xHarbour 1.0.0 - Bcc 6.3 - Gtwvw/Hwgui
DbfCdx/MySql
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: verificar integridade do dbf ???

Mensagem por Maligno »

Verificação realmente segura não existe pelos métodos tradicionais (pelo Clipper). A não ser a inclusão de um campo em que conste o hash do conteúdo do registro. Faço isso e funciona 100%. Aliás, não só previne (e avisa) a corrupção, mas também fraude. Claro que esse tipo de controle requer uma mudança no sistema de gravação do registro no programa todo. Isso pode ser simples ou complexo, dependendo apenas de como são feitas as gravações.
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Re: verificar integridade do dbf ???

Mensagem por alxsts »

Caros amigos,

como voces puderam observar, a função postada detecta corrupção mas somente se esta corrupção afetar o tamanho de algum registro (e por tabela o tamanho total do DBF). Ela testa multiplicando o tamanho de cada registro pelo total de registros. No caso de driver DBFNTX testa tambem a integridade do arquivo MEMO associado, caso seja localizado. Sem dúvida, o processo mais seguro é o uso de hash, conforme indicado pelo Maligno.
Fiz algumas melhorias na função e por este motivo posto novamente.
Esclareço que esta função não é de minha autoria. Peguei na net há algum tempo atrás, sem o nome do autor. Por isto não lhe credito a autoria.

[]´s
AlxSts

Código: Selecionar todos

//-------------------------------------------------------
//     Testar se o DBF a ser aberto é válido.
//
//        0 - Everything ok
//       -1 - File is corrupt
//       -2 - File does not exist
//       -3 - DBF file is set to read only
//       -4 - Memo file is missing
//       >0 - A DOS error
//        2 - File not found
//        3 - Path not found
//        4 - Too many files open
//        5 - Access denied
//        6 - Invalid handle
//        8 - Insufficient memory
//       15 - Invalid drive specified
//       19 - Attempted to write to a write-protected
//       21 - Drive not ready
//       23 - Data CRC error
//       29 - Write fault
//       30 - Read fault
//       32 - Sharing violation
//       33 - Lock Violation
//
//   Exemplo:  If ValidDBF( <xcFile>) != 0
//                Alert( <xcFile> +  " : " <cMessage> )
//             Endif
//
//--------------------------------------------------------------------------
Function ValidDbf( cFile )

   #define VALID_SIGNATURE_BYTES {   3, 131, 139, 245 }
   #define DBT_FILE_NEEDED_BYTES { 131, 139, 245      }
   #define MEMO_FILE_EXTENSIONS  { "DBT", "DPT", "FPT" }

   #include "SET.CH"
   #include "FILEIO.CH"

   Local cDir    := Set(_SET_DEFAULT)
   Local cBuf    := Space( 12 )
   Local nSign   := 0
   Local nReturn := 0
   Local nBlocks := 0
   Local nSize   := 0
   Local nRecs   := 0
   Local nRecSize:= 0
   Local nOffset := 0
   Local x
   Local nHandle

   nHandle := FOpen( cDir + cFile + ;
                If( At( ".", Upper( cFile ) ) > 0, "", ".DBF" ), FO_READWRITE + FO_SHARED )

   If nHandle != -1
      FRead( nHandle, @cBuf, 12 )
      nSize := FSeek(nHandle, 0, FS_END )
      FClose( nHandle )
      nSign := Asc( cBuf )
      If Ascan( VALID_SIGNATURE_BYTES, nSign ) > 0

         nRecs    := Bin2l( Subs( cBuf,  5, 4 ) )
         nRecSize := Bin2w( Subs( cBuf, 11, 2 ) )
         nOffset  := Bin2w( Subs( cBuf,  9, 2 ) )

         If nRecs > 0
            nReturn := If( Abs( ( nRecs * nRecSize ) + nOffset - nSize ) < 3, 0, -1 )
         Else
            nReturn := If( nOffset <= nSize + 1, 0, -1 )
         Endif
      Else
         nReturn := -1
      Endif

      If nReturn == 0
         If ( x := Ascan( DBT_FILE_NEEDED_BYTES, nSign ) ) > 0
            nReturn := -4
            nHandle := FOpen( cdir + cFile + "." + MEMO_FILE_EXTENSIONS[ x ], FO_READWRITE )
            If nHandle != -1
               If MEMO_FILE_EXTENSIONS[ x ] == "DBT"
                  cBuf    := Space( 4 )
                  FRead( nHandle, @cBuf, 4 )
                  nSize   := FSeek( nHandle, 0, FS_END )
                  nBlocks := Bin2l( cBuf ) * 512
                  If nSize <= ( nBlocks + 1 ) .and. nSize > ( nBlocks - 512 )
                     nReturn := 0
                  Endif
                  // Movi para depois do segundo Endif abaixo...
                  // FClose( nHandle )
               Else
                  nReturn := 0
               Endif
            // Para clareza no cod retorno, se não encontrou o Memo associado, retorna -4;
            // de outra forma retorna FError()
            ElseIf FError() != 2
               nReturn := FError()
            Endif
            FClose( nHandle )
         Endif
      Endif
   Else
      If Ferror() == 5
         nReturn := -3
      Else
         nReturn := Ferror()
      Endif
   Endif
Return nReturn
//------------------------------------------------------------------------------
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

verificar integridade do dbf ???

Mensagem por Pablo César »

A sua solução apresentada, não tem nada de errado apenas lê o arquivo em baixo nível e procura as informações do header do dbf, instrução como demostra esta tabela: http://www.dbase.com/KnowledgeBase/int/db7_file_fmt.htm, claro que se tiver alguns caracteres ilegíveis devido a uma corrupção de arquivo, poderia ainda ser aberto da forma tradicional e ser checado registro a registro, buscando por caracteres estranhos (não pertencentes ao alfabeto) dentro dos campos do dbf. Na minha opinião, eu nunca transmitiria um dbf, criaria um arquivo texto com separadores ou não. O modo textosempre é mais rápido e não precisaria tratar o arquivo como se fosse binário no caso de usar o FTP.
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Re: verificar integridade do dbf ???

Mensagem por alxsts »

Olá Pablo!

Na primeira versão postada da função, se ela conseguisse abrir o arquivo MEMO e o mesmo não fosse um .DBT (driver dbfntx), ela saia sem executar FClose( nHandle ). Porisso, movi esta instrução para depois do Endif, conforme comentário.
O lance de transmitir texto realmente é legal e o mais tradicionalmente utilizado, inclusive pelos bancos. Vide CNAB 400 e outros protocolos.

[]´s
AlxSts
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: verificar integridade do dbf ???

Mensagem por Maligno »

Detalhe: todo eMail é texto puro. Qualquer binário é convertido, seja para Base64 ou UUencode. Esses algoritmos são fáceis de implementar. Seria o ideal (e mais seguro) para montar um "pacote" a transmitir, do qual poderia fazer parte um hash para certificação do conteúdo recebido no destino.
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
Maurício Elias
Usuário Nível 3
Usuário Nível 3
Mensagens: 304
Registrado em: 12 Mai 2005 08:48

Re: verificar integridade do dbf ???

Mensagem por Maurício Elias »

Bom dia amigo.

Eu estou arjeando com senha e transmitindo (binary). Se desargear certinho na recepção, é pq está tudo ok.

Abraços.

_______
Maurício
Abraços.
_______
Maurício
TerraSoftware
Usuário Nível 3
Usuário Nível 3
Mensagens: 353
Registrado em: 28 Jul 2004 13:14
Localização: Cianorte-PR
Contato:

Re: verificar integridade do dbf ???

Mensagem por TerraSoftware »

Caros colegas, pelo visto temos dois assuntos distintos neste post:

1- Transmiçao de dados via ftp - eu uso este recurso tambem, da seguinte maneira: compacto os dbfs que quero transmitir em formato zip e depois transmito. Ao receber eu testo apenas a integridade do zip (existe funcao para isso), se o arquivo realmente estiver no formato zip é sinal que a transferencia foi legal, entaum descompacto e leio os dbfs, se o zip estiver corrompido entaum eu descarto o mesmo. Claro que isso nao funciona em 100% dos casos, mas com certeza, na grande maioria deles. Este procedimento tem funcionado muito bem com nós.

2- Integridade de um arquivo dbf. Este assunto sim, este é muito interessante mesmo, pois isso pode ajudar a resolver muitos outros problemas. Pergunto ao amigo maligno: implementar um campo hash e estar calculando o mesmo nao vai causar uma certa mentidao ao sistema? o que o amigo tem feito a este respeito? usa em todas as tabelas? ou apenas em tabelas criticas? por favor, fale mais sobre o assunto.
www.sisterra.com.br
xHarbour 1.0.0 - Bcc 6.3 - Gtwvw/Hwgui
DbfCdx/MySql
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Re: verificar integridade do dbf ???

Mensagem por asimoes »

Olá a Todos,


Existe algum exemplo de caso de uso usando o hash?

Eu costumo usar dbfs temporários, depois de muitos problemas com as bases reais, corrupção de dbf e indices.
Com os temporários a probabilidade de dar corrupção são minimos.

Para isso em cada aplicação tenho uma rotina de importação e somente uma estação (deifinida por parâmetros de sistema) faz a inclusão dos registros temporários para a base real. Desta forma o trafego em rede é bem reduzido. Outra forma é gerar um txt com os registros a serem incluidos e depois decarregar na base real.

[]´s
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Responder