Página 1 de 1

Rotina para transformar campos de arquivo

Enviado: 25 Abr 2011 09:27
por trooper7
Olá pessoal, bom dia!

Gostaria que me ajudassem a criar uma rotina em Clipper para abrir um arquivo .dbf, ler os campos deste arquivo, multiplicá-los por 100 e gravar novamente no arquivo, mas em campos diferentes dos originais. :-o

Creio que será preciso chamar um do while, ou alguma coisa assim, mas não tenho muita noção de como fazer isso. Estou voltando a mexer agora com programação/Clipper... :/

Agradeço desde já pela atenção!

Abraços!

Re: Rotina para transformar campos de arquivo

Enviado: 25 Abr 2011 11:13
por fladimir
Olá Colega....

Seria interessante fornecer mais detalhes como:

Exemplo de alguns campos contidos neste DBF, pois simplesmente multiplicar por 100 gera algumas dúvidas tipo:

Se for numérico seriam resultados e registros novos?
Caso caracter, variar todos os registros ou somente 01 e gerar 100 novos registros diferentes...
Este dbf teria somente 01 campo ou vários?
Etc.

Precisamos de mais parametros para ver se conseguimos auxiliar o colega.

Ficamos no aguardo,

Sucesso!!!

:)Pos

Re: Rotina para transformar campos de arquivo

Enviado: 25 Abr 2011 15:14
por alxsts
Olá!

Thiago:
segue o código conforme você explicou via MSN. Faça os ajustes necessários e teste.

Em futuros tópicos, por favor, observe a orientação do Fladimir. Ajuda bastante e torna o processo mais dinâmico.

Código: Selecionar todos

/* Layout original           Layout alterado
 "NCM",  "C", 31, 0          "NCM",  "C", 31, 0
 "SPORI","C", 13, 0          "SPORI","C,  13, 0
 "SPAJU","C", 14, 2          "SPAJU, "N", 14, 2
 "AL",   "C", 11, 2          "AL,    "N", 11, 2
 "BA",   "C", 11, 2          "BA,    "N", 11, 2
 "MG",   "C",  9, 0          "MG,    "N",  9, 2
 "MS",   "C", 11, 0          "MS,    "N", 11, 2
 "MT",   "C", 11, 0          "MT,    "N", 11, 2
 "RS",   "C", 11, 0          "RS,    "N", 11, 2
*/

#include "dbstruct.ch"

FUNCTION TblConv()

   LOCAL aStru, cFile := Space(8), lRet := .F., GetList := {}

   CLS

   SampleData()  // ### retirar depois dos testes ###

   @ 3,3 Say "Informe o nome do arquivo a converter:" ;
         Get cFile
   READ

   IF ! Empty( cFile )
      IF File( cFile + ".DBF" )

         USE ( cFile ) EXCLUSIVE NEW ALIAS Entrada

         If ! NetErr( cFile )
            // alterar a estrutura, da posição 3 em diante
            aStru := Entrada->( DbStruct() )

            AEval( aStru, { |e,p| aStru[ p, DBS_TYPE ] := "N", aStru[ p, DBS_DEC ] := 2  }, 3 )

            // cria o arquivo de saida
            cFile := RTrim( Left( cFile, 7 ) ) + "_"
            DbCreate( cFile, aStru )

            USE ( cFile ) EXCLUSIVE NEW ALIAS Saida

            If ! NetErr()
               // transferir registros
               WHILE ! Entrada->( Eof() )
                  Saida->( DbAppend() )
                  If ! NetErr()
                     Saida->ncm    := Entrada->ncm
                     Saida->spori  := Entrada->spori
                     Saida->spaju  := Val( Entrada->spaju ) / 100
                     Saida->al     := Val( Entrada->al    ) / 100
                     Saida->ba     := Val( Entrada->ba    ) / 100
                     Saida->mg     := Val( Entrada->mg    ) / 100
                     Saida->ms     := Val( Entrada->ms    ) / 100
                     Saida->mt     := Val( Entrada->mt    ) / 100
                     Saida->rs     := Val( Entrada->rs    ) / 100

                     Entrada->( DbSkip() )
                  Else
                     Alert( "Falha ao gravar arquivo de saida" )
                     EXIT
                  Endif
               ENDDO
               lRet := .T.
            Else
               Alert( "Falha ao abrir o arquivo de saida" )
            Endif
         Else
            Alert( "Falha ao abrir o arquivo de entrada" )
         Endif
      Else
         Alert( "Arquivo nao encontrado" )
      Endif
   Endif

   DbCloseAll()

   RETURN lRet
//------------------------------------------------------------------------------
PROCEDURE SampleData()

   // Criar massa de dados para teste - retirar depois dos testes

   LOCAL nInd, nVal

   DbCreate( "IVA", { { "NCM",   "C", 31, 0 }, ;
                      { "SPORI", "C", 13, 0 }, ;
                      { "SPAJU", "C", 14, 2 }, ;
                      { "AL",    "C", 11, 2 }, ;
                      { "BA",    "C", 11, 2 }, ;
                      { "MG",    "C",  9, 0 }, ;
                      { "MS",    "C", 11, 0 }, ;
                      { "MT",    "C", 11, 0 }, ;
                      { "RS",    "C", 11, 0 } ;
                    } ;
           )

   FOR nInd := 1 TO 100
      nVal := ( Val( StrTran( Left( Time(), 5 ), ":", "" ) ) * nInd ) / 1000

      USE IVA EXCLUSIVE NEW

      IVA->( DbAppend() )

      IVA->ncm   := "IVA " + LTrim ( Str( nInd ) )
      IVA->spori := "SPORI"
      IVA->spaju := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->al    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->ba    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->mg    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->ms    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->mt    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->rs    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
   NEXT

   IVA->( DbCloseArea() )

   RETURN
//------------------------------------------------------------------------------

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 10:53
por trooper7
Opa!
Muito obrigado pela atenção Fladimir e Alex!!!
Pode deixar que em futuras dúvidas eu serei mais completo ao me explicar. rs

Bom, agradeço novamente ao amigo Alex pelo código!
Compilei-o aqui, mas está acusando um erro na variável "DBS_TYPE", na seguinte linha:

Código: Selecionar todos

AEval( aStru, { |e,p| aStru[ p, DBS_TYPE ] := "N", aStru[ p, DBS_DEC ] := 2 }, 3 )
Tentei fuçar até achar uma solução, mas infelizmente desconheço os comandos utilizados nesta passagem :/
O que pode estar acontecendo?

Grato pela atenção!
Abraços!!!

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 10:55
por alxsts
Olá!

Certamente você não copiou o código completo. Faltou a linha:

Código: Selecionar todos

#include "dbstruct.ch"

Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 11:24
por Pablo César
está acusando um erro na variável "DBS_TYPE"
DBS_TYPE é uma constante que possui valor 2 mas coloque esse include que o Alexandre indicou pois irá encontrar outra constante DBS_DEC com valor 4.

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 11:26
por trooper7
Ah sim, Alex!
Mas quando incluo esta linha no programa, o seguinte erro é apresentado na compilação:
Can't open #include file: 'dbstruct.ch'
Portanto, está faltando adicionar alguma biblioteca às configurações do Clipper aqui, é isso?

Até porque, iniciando as variáveis manualmente, o programa apresenta o seguinte erro:
Argument error: array assign
Provavelmente pela falta do dbstruct.ch mesmo...
Como posso resolver isto?

Valeeeu! Abraços!

Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 11:29
por Pablo César
Então apenas substitua as constantes pelo seu valor <veja a minha mensagem anterior>.

Aqui deixo o arquivo header que deverá estar em C:\CLIPPER5\INCLUDE

Código: Selecionar todos

/***
*
*  Dbstruct.ch
*
*  DBSTRUCT() function definitions
*
*  Copyright (c) 1990-1993, Computer Associates International, Inc.
*  All rights reserved.
*
*/


// Subscripts for field structure array
#define DBS_NAME		1
#define DBS_TYPE		2
#define DBS_LEN	 	3
#define DBS_DEC	 	4

// Length of array
#define DBS_ALEN		4

#define _DBSTRUCT_CH

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 12:04
por trooper7
Olá Pablo, obrigado pela ajuda, amigão!

O código funcionou agora, compilou e executou.
Porém, só está fazendo a operação de multiplicação no primeiro campo... nos demais, quando passado o tipo para Numérico, ficam zerados "0.00".

O arquivo original tem a seguinte estrutura e layout:
"NCM" , "C", 31, 0
"SPORI", "C", 13, 0
"SPAJU", "C", 14, 2
"AL", "C", 11, 2
"BA", "C", 11, 2
"MG", "C", 9 , 0
"MS", "C", 11, 0
"MT", "C", 11, 0
"RS", "C", 11, 0
O programa deverá alterar somente do campo "SPAJU" em diante.
Mas ao executar, somente este campo ("SPAJU") é alterado.
O que há de errado?

Agradeço pela atenção de todos!
Abraçoos!!!

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 12:48
por alxsts
Olá!
trooper7 escreveu:Mas quando incluo esta linha no programa, o seguinte erro é apresentado na compilação:
Can't open #include file: 'dbstruct.ch'
Para gerar aplicações em qualquer linguagem, o ambiente para execução do compilador e linkeditor deverá ser configurado adequadamente. Procure no fórum que tem vários tópicos relacionados. No caso específico do erro que você obteve, faltou configurar o path do diretório include da tua instalação. Exemplo: Set Include=C:\Clipper5\Include.
trooper7 escreveu:O programa deverá alterar somente do campo "SPAJU" em diante. Mas ao executar, somente este campo ("SPAJU") é alterado.
O que há de errado?
Executando o programa da forma como foi postado, não é isto que ocorre.
Arquivo de testes antes da alteração:

Código: Selecionar todos

ı══════════════════════════════════════════════════════════════════════════════©
│                                                  Record 1/100                │
│NCM                               SPORI           SPAJU            AL         │
ã════════════════════════════════Ð═══════════════Ð════════════════Ð════════════Á
│IVA 1                           │ SPORI         │        30      │        30  │
│IVA 2                           │ SPORI         │        61      │        61  │
│IVA 3                           │ SPORI         │        91      │        91  │
│IVA 4                           │ SPORI         │       121      │       121  │
│IVA 5                           │ SPORI         │       152      │       152  │
│IVA 6                           │ SPORI         │       182      │       182  │
│IVA 7                           │ SPORI         │       212      │       212  │
│IVA 8                           │ SPORI         │       243      │       243  │
│IVA 9                           │ SPORI         │       273      │       273  │
│IVA 10                          │ SPORI         │       303      │       303  │
│IVA 11                          │ SPORI         │       334      │       334  │
Arquivo de testes após a alteração:

Código: Selecionar todos

ã════════════════════════════════Ð═══════════════Ð════════════════Ð════════════Á
│IVA 1                           │ SPORI         │           0.30 │        0.30│
│IVA 2                           │ SPORI         │           0.61 │        0.61│
│IVA 3                           │ SPORI         │           0.91 │        0.91│
│IVA 4                           │ SPORI         │           1.21 │        1.21│
│IVA 5                           │ SPORI         │           1.52 │        1.52│
│IVA 6                           │ SPORI         │           1.82 │        1.82│
│IVA 7                           │ SPORI         │           2.12 │        2.12│
│IVA 8                           │ SPORI         │           2.43 │        2.43│
│IVA 9                           │ SPORI         │           2.73 │        2.73│
│IVA 10                          │ SPORI         │           3.03 │        3.03│
│IVA 11                          │ SPORI         │           3.34 │        3.34│
Se não é isso que você precisa, forneça mais detalhes ou altere você mesmo. Agora está mais fácil, não?

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 14:44
por trooper7
Opa, Alex!
Já configurei corretamente o ambiente de desenvolvimento aqui, pesquisei sobre e agora está tudo certo. Obrigado!

Com relação ao código, o que eu preciso, na verdade, é que os valores sejam multiplicados por 100, e não divididos como estava no exemplo.
Foi isso que alterei.

Porém, pegando o meu arquivo de dados, somente o campo 'SPAJU' é alterado, os demais não.
Mesmo comentando ele na operação, os outros campos são somente transformados em '0.00'.

Analisei o código e o arquivo, e não consegui encontrar uma causa eminente para isto.
A única diferença do campo 'SPAJU' para os demais é que este possui tamanho 14.
Quando eu altero os outros campos, para que fiquem com as mesmas características do 'SPAJU' (tipo, tamanho, decimal) e quando executo o programa novamente, ele apresenta o erro: "Data width error".

Portanto, não sei o que pode estar errado. :/

Agradeço imensamente por toda ajuda fornecida!
Grande abraço!

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 15:03
por alxsts
Olá!

Você pediu para dividir por 100 e eu fiz. Agora, se é para multiplicar, verifique se cada campo do teu DBF comporta o conteúdo multiplicado por 100. Certamente não comporta e está estourando e dando a mensagem "Data width error".

O código que passei cria uma nova estrutura igual à existente. Altere para aumentar o tamanho do campo:

Código: Selecionar todos

AEval( aStru, { |e,p| aStru[ p, DBS_TYPE ] := "N", ;
                      aStru[ p, DBS_LEN ] += 2 }, ;
                      aStru[ p, DBS_DEC ] := 2 }, 3 ) 
Precisa alterar as linhas onde os valores dos campos são divididos. Acho que você já fez isto.

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 16:40
por trooper7
Opaaaa, Alex!
Agora está funcionando, amigão!

Tudo certinho, era o tamanho dos campos do arquivo criado mesmo.
Nem sei como agradecer, valeu mesmo!

O importante é que pedindo a ajuda de vocês, eu aprendo diversas funções e comandos dos quais eu nem imaginava existir!
Ainda bem que nós iniciantes temos o fórum aqui e o grandioso Expert Guide, sempre salvando vidas! rs

Muito obrigado a todos pela ajuda, muito obrigado mesmo!
Um ótimo fim de semana!

Grande abraço! :D

OFF TOPIC - Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 17:35
por Pablo César
O importante é que pedindo a ajuda de vocês, eu aprendo diversas funções e comandos dos quais eu nem imaginava existir!
Ainda bem que nós iniciantes temos o fórum aqui e o grandioso Expert Guide, sempre salvando vidas! rs
Realmente aqui é uma grande fonte de informações e muitos colegas bem dispostos a ajudar, assim como o Alexandre. Só queria mesmo saber Thiago, você tem mesmo 18 anos ? Se for, parabéns pela sua ocupação. Muitos jovens desperdizam o seu tempo com bobagens. Espero que você cresça cada vez mais em programação. Imaginem se nessa idade ja está programando, então o cara vai ser fera quando chegar a nossa idade... Parabéns, não desista nunca, avalie sempre todas as ferramentas de programação, estude várias linguagens e de preferência seja um altruísta sempre, participe em fóruns. Terá sempre o nosso apoio.

Re: Rotina para transformar campos de arquivo

Enviado: 28 Abr 2011 18:06
por alxsts
Olá!

Corrigindo uma falha:
Na função SampleData(), a abertura do arquivo ficou dentro do FOR...NEXT...
Segue a versão final, com os últimos ajustes:

Código: Selecionar todos

/* Layout original           Layout alterado
 "NCM",  "C", 31, 0          "NCM",  "C", 31, 0
 "SPORI","C", 13, 0          "SPORI","C,  13, 0
 "SPAJU","C", 14, 2          "SPAJU, "N", 14, 2
 "AL",   "C", 11, 2          "AL,    "N", 11, 2
 "BA",   "C", 11, 2          "BA,    "N", 11, 2
 "MG",   "C",  9, 0          "MG,    "N",  9, 2
 "MS",   "C", 11, 0          "MS,    "N", 11, 2
 "MT",   "C", 11, 0          "MT,    "N", 11, 2
 "RS",   "C", 11, 0          "RS,    "N", 11, 2
*/

#include "dbstruct.ch"

FUNCTION TblConv()

   LOCAL aStru, cFile := PadR( "IVA", 8 ), lRet := .F., GetList := {}

   CLS

   SampleData()  // ### retirar depois dos testes ###

   @ 3,3 Say "Informe o nome do arquivo a converter:" ;
         Get cFile
   READ

   IF ! Empty( cFile )
      IF File( cFile + ".DBF" )

         USE ( cFile ) EXCLUSIVE NEW ALIAS Entrada

         If ! NetErr( cFile )
            // alterar a estrutura, da posição 3 em diante
            aStru := Entrada->( DbStruct() )


            AEval( aStru, { |e,p| aStru[ p, DBS_TYPE ] := "N", ;
                                  aStru[ p, DBS_LEN  ] += 2 }, ;
                                  aStru[ p, DBS_DEC  ] := 2 }, 3 ) 


            // cria o arquivo de saida
            cFile := RTrim( Left( cFile, 7 ) ) + "_"
            DbCreate( cFile, aStru )

            USE ( cFile ) EXCLUSIVE NEW ALIAS Saida

            If ! NetErr()
               // transferir registros
               WHILE ! Entrada->( Eof() )
                  Saida->( DbAppend() )
                  If ! NetErr()
                     Saida->ncm    := Entrada->ncm
                     Saida->spori  := Entrada->spori
                     Saida->spaju  := Val( Entrada->spaju ) * 100
                     Saida->al     := Val( Entrada->al    ) * 100
                     Saida->ba     := Val( Entrada->ba    ) * 100
                     Saida->mg     := Val( Entrada->mg    ) * 100
                     Saida->ms     := Val( Entrada->ms    ) * 100
                     Saida->mt     := Val( Entrada->mt    ) * 100
                     Saida->rs     := Val( Entrada->rs    ) * 100

                     Entrada->( DbSkip() )
                  Else
                     Alert( "Falha ao gravar arquivo de saida" )
                     EXIT
                  Endif
               ENDDO
               lRet := .T.
            Else
               Alert( "Falha ao abrir o arquivo de saida" )
            Endif
         Else
            Alert( "Falha ao abrir o arquivo de entrada" )
         Endif
      Else
         Alert( "Arquivo nao encontrado" )
      Endif
   Endif

   DbCloseAll()

   RETURN lRet
//------------------------------------------------------------------------------
PROCEDURE SampleData()

   // Criar massa de dados para teste - retirar depois dos testes

   LOCAL nInd, nVal

   DbCreate( "IVA", { { "NCM",   "C", 31, 0 }, ;
                      { "SPORI", "C", 13, 0 }, ;
                      { "SPAJU", "C", 14, 2 }, ;
                      { "AL",    "C", 11, 2 }, ;
                      { "BA",    "C", 11, 2 }, ;
                      { "MG",    "C",  9, 0 }, ;
                      { "MS",    "C", 11, 0 }, ;
                      { "MT",    "C", 11, 0 }, ;
                      { "RS",    "C", 11, 0 } ;
                    } ;
           )

   USE IVA EXCLUSIVE NEW

   FOR nInd := 1 TO 100
      nVal := ( Val( StrTran( Left( Time(), 5 ), ":", "" ) ) * nInd ) / 1000

      IVA->( DbAppend() )

      IVA->ncm   := "IVA " + LTrim ( Str( nInd ) )
      IVA->spori := "SPORI"
      IVA->spaju := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->al    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->ba    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->mg    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->ms    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->mt    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
      IVA->rs    := Str( ( nVal * Val( Right( Time(), 2 ) ) ), 9, 0 )
   NEXT

   IVA->( DbCloseArea() )

   RETURN
//------------------------------------------------------------------------------
Valeu pelo incentivo Pablo.