Página 1 de 1

verificar integridade do dbf ???

Enviado: 25 Jun 2009 15:56
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 ...

Re: verificar integridade do dbf ???

Enviado: 25 Jun 2009 16:07
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.

Re: verificar integridade do dbf ???

Enviado: 25 Jun 2009 18:55
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

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

Enviado: 27 Jun 2009 09:17
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

Re: verificar integridade do dbf ???

Enviado: 27 Jun 2009 16:02
por alxsts
Olá Adilson.

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

[]´s
AlxSts

verificar integridade do dbf ???

Enviado: 28 Jun 2009 05:50
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

Re: verificar integridade do dbf ???

Enviado: 30 Jun 2009 10:36
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?

Re: verificar integridade do dbf ???

Enviado: 30 Jun 2009 10:46
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.

Re: verificar integridade do dbf ???

Enviado: 30 Jun 2009 13:47
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
//------------------------------------------------------------------------------

verificar integridade do dbf ???

Enviado: 30 Jun 2009 16:55
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.

Re: verificar integridade do dbf ???

Enviado: 30 Jun 2009 17:35
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

Re: verificar integridade do dbf ???

Enviado: 30 Jun 2009 17:38
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.

Re: verificar integridade do dbf ???

Enviado: 01 Jul 2009 08:12
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

Re: verificar integridade do dbf ???

Enviado: 01 Jul 2009 09:18
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.

Re: verificar integridade do dbf ???

Enviado: 01 Jul 2009 13:42
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