Clipper On Line • Ver Tópico - Recuperar DBF danificado.

Recuperar DBF danificado.

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

 

Recuperar DBF danificado.

Mensagempor Itamar M. Lins Jr. » 04 Nov 2020 09:48

Olá!
Peguei no forum internacional.
 /*
     Author Edmond Broux

     In a dbf file characters from chr (0) to chr (31) indicate a corrupt record.
     The program replaces corrupted characters with a space and destroys the file.
     This can damage the index files.
     */

PROCEDURE Main ( xFile , xNbRecord )
LOCAL I,aRet

   IF Empty(xFile)
      QOut( "file name ???" )
      WAIT
      RETURN
   ENDIF

   QOut( "file name = " , xFile ) // file name

     *
     *  aRet=FIX_CORRUPTED_DBF( xFile , xNbRecord )
     *  xNbRecord = number of files to be processed in one pass
     *  aRet[1,1] = file name
     *  aRet[1,2] = number of records
     *  aRet[1,3] = number of corrupted records
     *  aRet[1,4] = number of characters replaced
     *  for i=2 to len(aRet)
     *     aRet[i,1] = recno()
     *     aRet[i,2] = number of characters replaced
     *  next
     *

   xNbRecord=IIF( Empty(xNbRecord) , 10 , VAL(xNbRecord) )

   aRet=FIX_CORRUPTED_DBF( xFile , xNbRecord )

   QOut( "file name = " , aRet[1,1] ) // file name
   QOut( "number of records = " , aRet[1,2] ) // number of records
   QOut( "number of corrupted records = " , aRet[1,3] ) // number of corrupted records
   QOut( "number of characters replaced = " , aRet[1,4] ) // number of characters replaced
   QOut()
   FOR I=2 to len(aRet)
      QOut( "recno() = " , aRet[i,1] ) //  recno()
      QQOut( " number of characters replaced = " , aRet[i,2] ) // number of characters replaced
   NEXT
   QOut()
   WAIT
RETURN

   *
   *
   *

   /*  File seek mode flags fileio.ch  */
   #define FS_SET             0           /* Seek from beginning of file */
   #define FS_RELATIVE        1           /* Seek from current file pointer */
   #define FS_END             2           /* Seek from end of file */

   *
   *
   *
FUNCTION FIX_CORRUPTED_DBF ( xFile , xNbRecord )
STATIC xChrList:=Chr(00)+Chr(01)+Chr(02)+Chr(03)+Chr(04)+Chr(05)+Chr(06)+Chr(07)+Chr(08)+Chr(09)+;
                 Chr(10)+Chr(11)+Chr(12)+Chr(13)+Chr(14)+Chr(15)+Chr(16)+Chr(17)+Chr(18)+Chr(19)+;
                 Chr(20)+Chr(21)+Chr(22)+Chr(23)+Chr(24)+Chr(25)+Chr(26)+Chr(27)+Chr(28)+Chr(29)+;
                 Chr(30)+Chr(31)
LOCAL I,X,hFile,xPos,aRet,xLenFile,xNbChar,xDelChr,IsBug,aHead
LOCAL xRecCount,xHeader,xFCount,xRecSize,xLenBuffer,xRecno

   xFile=iif( Empty(xFile) , "" , xFile )
   xNbRecord=iif( Empty(xNbRecord) , 10  , xNbRecord )

aRet={ { xFile , 0 , 0 , 0 } }
IF Empty( xFile )
   RETURN aRet
ELSEIF .NOT. File( xFile )
   RETURN aRet
ENDIF
   *
   aHead=CORRUPTED_HEADER_DBF( xFile )
   *
IF .NOT. aHead[1]
   RETURN aRet
ENDIF

xRecCount=aHead[4]    // RecCount()
xHeader=aHead[5]      // Header()
xFCount=aHead[6]      // FCount()
xRecSize=aHead[7]     // RecSize()
xLenBuffer=xRecSize * xNbRecord

aRet={ { xFile , xRecCount , 0 , 0 } }

hFile=FOpen( xFile , 2 + 16 ) // READ_WRITE + EXCLUSIVE

   FSeek( hFile , xHeader , FS_SET )
   xPos=xHeader
   xLenFile=hb_FSize(xFile)
   xDelChr=" "

PRIVATE xBuffer:=SPACE(xLenBuffer)
PRIVATE xChar:=" "

xRecno=0
DO WHILE .T.

   NbOctet=FRead( hFile , @xBuffer , xLenBuffer )

   IF NbOctet=0
      xRecno=xRecCount
      EXIT
   ENDIF

   IF .NOT. CORRUPTED_BUFFER( xBuffer )
      xPos=xPos+NbOctet
      IF NbOctet=xLenBuffer
         xRecno=xRecno+xNbRecord
      ELSE
         xRecno=xRecno+Int(NbOctet / xRecSize)
      ENDIF
      LOOP
   ENDIF

   FSeek( hFile , -NbOctet , FS_RELATIVE )

   xNbChar=0
   IsBug="N"

   FOR I=1 TO NbOctet
      X=FRead( hFile , @xChar , FS_RELATIVE )
      xPos=xPos+X
      xNbChar=iif( xNbChar=xRecSize , 1 , xNbChar+1 )

      IF I=NbOctet .AND. xPos=xLenFile .AND. xChar=Chr(26)  // caractere valide fin de fichier
         EXIT
      ENDIF

      IF xNbChar=1
         IsBug="N"
         xDelChr=xChar
         xRecno=xRecno+1
      ENDIF

      IF .NOT. xChar $ xChrList  // valid character
         IF xNbChar=xRecSize .AND. IsBug="O"
            DEL_CORRUPTED_RECORD( hFile , xDelChr , xRecSize )
         ENDIF
         LOOP
      ENDIF

      IF IsBug="N"
         aRet[1,3]=aRet[1,3]+1 // number of corrupted records
         AAdd( aRet , { xRecno , 0 } )
         IsBug="O"
      ENDIF

      aRet[1,4]=aRet[1,4]+1 // number of characters replaced
      ATail(aRet)[2]=ATail(aRet)[2]+1 // number of characters replaced

      // replace the wrong character with a space
      FSeek( hFile , -1 , FS_RELATIVE )
      FWrite( hFile , " " )

      IF xNbChar=xRecSize
         // delete corrupted record
         DEL_CORRUPTED_RECORD( hFile , xDelChr , xRecSize )
      ENDIF

   NEXT
ENDDO
FClose( hFile )
RETURN aRet
   *
   *
   *
FUNCTION DEL_CORRUPTED_RECORD ( hFile , xDelChr , xRecSize )
IF xDelChr<>"*"
   FSeek( hFile , -(xRecSize) , FS_RELATIVE )
   FWrite( hFile , "*" )
   FSeek( hFile , (xRecSize-1) , FS_RELATIVE )
   RETURN .T.
ENDIF
RETURN .F.
   *
   *
   *
FUNCTION CORRUPTED_BUFFER ( xBuffer )
STATIC Chr_00 := Chr( 00 )
STATIC Chr_01 := Chr( 01 )
STATIC Chr_02 := Chr( 02 )
STATIC Chr_03 := Chr( 03 )
STATIC Chr_04 := Chr( 04 )
STATIC Chr_05 := Chr( 05 )
STATIC Chr_06 := Chr( 06 )
STATIC Chr_07 := Chr( 07 )
STATIC Chr_08 := Chr( 08 )
STATIC Chr_09 := Chr( 09 )
STATIC Chr_10 := Chr( 10 )
STATIC Chr_11 := Chr( 11 )
STATIC Chr_12 := Chr( 12 )
STATIC Chr_13 := Chr( 13 )
STATIC Chr_14 := Chr( 14 )
STATIC Chr_15 := Chr( 15 )
STATIC Chr_16 := Chr( 16 )
STATIC Chr_17 := Chr( 17 )
STATIC Chr_18 := Chr( 18 )
STATIC Chr_19 := Chr( 19 )
STATIC Chr_20 := Chr( 20 )
STATIC Chr_21 := Chr( 21 )
STATIC Chr_22 := Chr( 22 )
STATIC Chr_23 := Chr( 23 )
STATIC Chr_24 := Chr( 24 )
STATIC Chr_25 := Chr( 25 )
STATIC Chr_26 := Chr( 26 )
STATIC Chr_27 := Chr( 27 )
STATIC Chr_28 := Chr( 28 )
STATIC Chr_29 := Chr( 29 )
STATIC Chr_30 := Chr( 30 )
STATIC Chr_31 := Chr( 31 )
   *
   * in a dbf file characters from chr (0) to chr (31) indicate a corrupt record.
   *
    IF Chr_00 $ xBuffer ;  RETURN .T.
ELSEIF Chr_01 $ xBuffer ;  RETURN .T.
ELSEIF Chr_02 $ xBuffer ;  RETURN .T.
ELSEIF Chr_03 $ xBuffer ;  RETURN .T.
ELSEIF Chr_04 $ xBuffer ;  RETURN .T.
ELSEIF Chr_05 $ xBuffer ;  RETURN .T.
ELSEIF Chr_06 $ xBuffer ;  RETURN .T.
ELSEIF Chr_07 $ xBuffer ;  RETURN .T.
ELSEIF Chr_08 $ xBuffer ;  RETURN .T.
ELSEIF Chr_09 $ xBuffer ;  RETURN .T.
ELSEIF Chr_10 $ xBuffer ;  RETURN .T.
ELSEIF Chr_11 $ xBuffer ;  RETURN .T.
ELSEIF Chr_12 $ xBuffer ;  RETURN .T.
ELSEIF Chr_13 $ xBuffer ;  RETURN .T.
ELSEIF Chr_14 $ xBuffer ;  RETURN .T.
ELSEIF Chr_15 $ xBuffer ;  RETURN .T.
ELSEIF Chr_16 $ xBuffer ;  RETURN .T.
ELSEIF Chr_17 $ xBuffer ;  RETURN .T.
ELSEIF Chr_18 $ xBuffer ;  RETURN .T.
ELSEIF Chr_19 $ xBuffer ;  RETURN .T.
ELSEIF Chr_20 $ xBuffer ;  RETURN .T.
ELSEIF Chr_21 $ xBuffer ;  RETURN .T.
ELSEIF Chr_22 $ xBuffer ;  RETURN .T.
ELSEIF Chr_23 $ xBuffer ;  RETURN .T.
ELSEIF Chr_24 $ xBuffer ;  RETURN .T.
ELSEIF Chr_25 $ xBuffer ;  RETURN .T.
ELSEIF Chr_26 $ xBuffer ;  RETURN .T.
ELSEIF Chr_27 $ xBuffer ;  RETURN .T.
ELSEIF Chr_28 $ xBuffer ;  RETURN .T.
ELSEIF Chr_29 $ xBuffer ;  RETURN .T.
ELSEIF Chr_30 $ xBuffer ;  RETURN .T.
ELSEIF Chr_31 $ xBuffer ;  RETURN .T.
ENDIF
RETURN .F.
   *
   *
   *

   /*
   FUNCTION CORRUPTED_BUFFER ( xBuffer )
   LOCAL I
   FOR I=0 TO 31
      IF Chr(I) $ xBuffer
         RETURN .T.
      ENDIF
   NEXT
   RETURN .T.
   */

   *
   *
   *
FUNCTION CORRUPTED_HEADER_DBF ( XFILE )
LOCAL I,X,hFile,aVerDbf,xVerDbf
LOCAL xYear,xMonth,xDay,xUpdate
LOCAL xRecCount,xHeader,xRecSize
LOCAL aHead

   * structure du fichier dbf
   *
   * structure de l'entete
   * 32 premiers octets du fichier :
   * 1 type de dbf
   * 2 annee de la derniere mise a jour
   * 3 mois de la derniere mise a jour
   * 4 jour de la derniere mise a jour
   * 5,6,7,8 nombre de fiches saisies
   * 9,10 longueur de l'entete header()
   * 11,12 longueur d'une fiche recsize()
   * 13,,,,32
   * longueur de l'entete header() = 32 + (32*nombre de champs) + 2
   * puis 2 octets chr(13)+chr(0)
   * puis 32 octets par champs
   *
   * ensuite les fiches saisies
   * le premier caractere de la fiche indique si la fiche est valide ou supprimee
   * l'espace " " = valide, l'etoile "*" = fiche supprimee
   * ensuite tous les champs de la fiche sans aucun separateur
   *
   * fin de fichier avec chr(26)
   *

   *         File header
   *    |=======================|
   *  1 | Dbf Version Number    |
   *    |-----------------------|
   *  2 | Date of last update   |
   *  3 |      YYMMDD           |
   *  4 |                       |
   *    |-----------------------|
   *  5 | Number of records     |
   *  6 | in data file          |
   *  7 | ( 32 bits )           |
   *  8 |                       |
   *    |-----------------------|
   *  9 | Length of header      |
   * 10 | structure ( 16 bits ) |
   *    |-----------------------|
   * 11 | Length of each record |
   * 12 | ( 16 bits )           |
   *    |-----------------------|

           * hexa , bit masq , ascci
aVerDbf={ { 0x02 , "00000010" ,  2 , ""  , "foxbase" } ,;
          { 0x03 , "00000011" ,  3 , ""  , "file without dbt" } ,;
          { 0x04 , "00000100" ,  4 , ""  , "dbase IV without memofile" } ,;
          { 0x05 , "00000101" ,  5 , ""  , "dbase V  without memofile" } ,;
          { 0x07 , "00000111" ,  7 , ""  , "visual object for dbase III without memofile" } ,;
          { 0x30 , "00110000" , 48 , "0" , "visual foxpro" } ,;
          { 0x30 , "00110000" , 48 , "0" , "visual foxpro with DBC" } ,;
          { 0x31 , "00110001" , 49 , "1" , "visual foxpro with autoincrement field" } ,;
          { 0x43 , "01000011" , 67 , "C" , ".dbv memo var size Flagship" } ,;
          { 0x7B , "01111011" ,123 , "{" , "dbase IV with memo" } ,;
          { 0x83 , "10000011" ,131 , "" , "file with dbt" } ,;
          { 0x83 , "10000011" ,131 , "" , "dbase III with memo" } ,;
          { 0x87 , "10000111" ,135 , "" , "visual object for dbase III with memofile" } ,;
          { 0x8B , "10001011" ,139 , "" , "dbase IV with memo" } ,;
          { 0x8E , "10001110" ,142 , "" , "dbase IV with SQL table" } ,;
          { 0xB3 , "10110011" ,179 , "" , ".dbv memo and dbt memo flagship" } ,;
          { 0xE5 , "11100101" ,229 , "" , "clipper six driver with SMT memo" } ,;
          { 0xF5 , "11110101" ,245 , "" , "foxpro with memo " } ,;
          { 0xFB , "11111011" ,251 , "" , "foxpro ???" } }

xYear=0
xMonth=0
xDay=0
xUpdate=""
xRecCount=""
xHeader=""
xRecSize=""
   *
   *
   aHead={ .F. , "fichier de type inconnu" , "00000000" , 0 , 0 , 0 , 0 , 0 }
   *
   *
PRIVATE xChr:=" "
hFile := FOpen( XFILE , 2+16) // READ_WRITE + EXCLUSIVE
FSeek( hFile , 0 , 0 )

FOR I=1 TO  32

   X=FRead( hFile , @xChr , FS_RELATIVE )
   IF X=0
      RETURN aHead
   ENDIF

   IF I=1
      IF Asc(xChr)=0
         RETURN aHead
      ENDIF
      xVerDbf=""
      FOR X=1 TO LEN(aVerDbf)
          IF Asc(xChr)=aVerDbf[X,3]
             xVerDbf=aVerDbf[X,5]
             EXIT
          ENDIF
      NEXT
      IF Empty(xVerDbf)
         RETURN aHead
      ENDIF
      aHead[2]=xVerDbf
   ELSEIF I=2
      xYear=1900+Asc(xChr)
      IF xYear<1900 .AND. xYear>2155
         RETURN aHead
      ENDIF
   ELSEIF I=3
      xMonth=Asc(xChr)
      IF xMonth<0 .AND. xMonth>12
         RETURN aHead
      ENDIF
   ELSEIF I=4
      xDay=Asc(xChr)
      IF xDay<0 .AND. xDay>31
         RETURN aHead
      ENDIF
      xUpdate=STRZERO(xYear,4)+STRZERO(xMonth,2)+STRZERO(xDay,2)
      IF Empty( hb_StoD(xUpdate) )
         RETURN aHead
      ENDIF
      aHead[3]=CToD(xUpdate)        // LUpdate()
   ELSEIF I>=5 .AND. I<=8
      xRecCount=xRecCount+xChr
      IF I=8
         aHead[4]=Bin2U(xRecCount)  // RecCount()  Bin2U hbxpp.lib
      ENDIF
   ELSEIF I>=9 .AND. I<=10
      xHeader=xHeader+xChr
      IF I=10
         IF Bin2L(xHeader)<66  // 32 + 32 pour 1 champ + 2 fin de liste des champs
            RETURN aHead
         ENDIF
         aHead[5]=Bin2L(xHeader)           // Header()
         aHead[6]=(aHead[5]-32-2) / 32     // FCount()
      ENDIF
   ELSEIF I>=11 .AND. I<=12
      xRecSize=xRecSize+xChr
      IF I=12
         IF Bin2L(xRecSize)<2  // au moins deux caracteres
            RETURN aHead
         ENDIF
         aHead[7]=Bin2L(xRecSize)  // RecSize()
      ENDIF
   ENDIF
NEXT
FClose( hFile )

aHead[1]=.T.
RETURN aHead
   *
   *
   *


Não testei.

Saudações,
Itamar M. Lins Jr.
Avatar de usuário

Itamar M. Lins Jr.
Colaborador

Colaborador
 
Mensagens: 6927
Data de registro: 30 Mai 2007 11:31
Cidade/Estado: Ilheus Bahia
Curtiu: 309 vezes
Mens.Curtidas: 503 vezes



Retornar para Contribuições, Dicas e Tutoriais

Quem está online

Usuários vendo este fórum: Nenhum usuário registrado online e 10 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro