Protheus :: Alternativa às Funções do Tipo FT_F*
Outro dia precisei ler um arquivo, através das funções FT_F* e, surpreso, descobri que ela possui limitações: Função: FT_FReadLn (Lê e retorna uma linha de texto do arquivo aberto pela função FT_FUse(). As linhas do texto, são delimitadas pela sequência de caracteres CRLF (chr(13)+chr(10)) ou apenas LF (chr(10)), e o tamanho máximo de cada linha é 1022 bytes.).
O arquivo que estava tentando ler superava, em muito, a quantidade de caracteres suportado pela FT_FReadLn: 2668 no total ( quase 3 vezes mais ).
Para a solução do problema, desenvolvi a classe fT com as mesmas semelhanças as funções FT_F* e sem as limitações impostas por esta.
Abaixo um exemplo de uso
#INCLUDE "PROTHEUS.CH" #INCLUDE "TRYEXCEPTION.CH" #INCLUDE "FILEIO.CH" /*/ CLASS: fT Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Alternativa aas funcoes tipo FT_F* devido as limitacoes apontadas em (http://tdn.totvs.com.br/kbm#9734) Sintaxe: ft():New() : Objeto do Tipo fT /*/ CLASS fT FROM LongClassName DATA aLines DATA cCRLF DATA cFile DATA cLine DATA cClassName DATA nRecno DATA nfHandle DATA nFileSize DATA nLastRecno DATA nBufferSize METHOD New() CONSTRUCTOR METHOD ClassName() METHOD ft_fUse( cFile ) METHOD ft_fOpen( cFile ) METHOD ft_fClose() METHOD ft_fAlias() METHOD ft_fExists( cFile ) METHOD ft_fRecno() METHOD ft_fSkip( nSkipper ) METHOD ft_fGoTo( nGoTo ) METHOD ft_fGoTop() METHOD ft_fGoBottom() METHOD ft_fLastRec() METHOD ft_fRecCount() METHOD ft_fEof() METHOD ft_fBof() METHOD ft_fReadLn() METHOD ft_fReadLine() METHOD ft_fError( cError ) METHOD ft_fSetCRLF( cCRLF ) METHOD ft_fSetBufferSize( nBufferSize ) END CLASS User Function ft() Return( NIL ) /*/ METHOD: New Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: CONSTRUCTOR Sintaxe: ft():New() : Object do Tipo fT /*/ METHOD New() CLASS fT Self:aLines := Array(0) Self:cFile := "" Self:cLine := "" Self:cClassName := "FT" Self:nRecno := 0 Self:nLastRecno := 0 Self:nfHandle := -1 Self:nFileSize := 0 Self:ft_fSetCRLF() Self:ft_fSetBufferSize() Return( Self ) /*/ METHOD: ClassName Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Retornar o Nome da Classe Sintaxe: ft():ClassName() : Retorna o Nome da Classe /*/ METHOD ClassName() CLASS fT Return( Self:cClassName ) /*/ METHOD: ft_fUse Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Abrir o Arquivo Passado como Parametro Sintaxe: ft():ft_fUse( cFile ) : nfHandle ( nfHandle > 0 True, False) /*/ METHOD ft_fUse( cFile ) CLASS fT TRYEXCEPTION IF !( Self:ft_fExists( cFile ) ) BREAK EndIF Self:ft_fOpen( cFile ) CATCHEXCEPTION Self:ft_fClose() ENDEXCEPTION Return( Self:nfHandle ) /*/ METHOD: ft_fOpen Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Abrir o Arquivo Passado como Parametro Sintaxe: ft():ft_fOpen( cFile ) : nfHandle ( nfHandle > 0 True, False) /*/ METHOD ft_fOpen( cFile ) CLASS fT TRYEXCEPTION IF !( Self:ft_fExists( cFile ) ) BREAK EndIF Self:cFile := cFile Self:nfHandle := fOpen( Self:cFile , FO_READ ) IF ( Self:nfHandle <= 0 ) BREAK EndIF Self:nFileSize := fSeek( Self:nfHandle , 0 , FS_END ) fSeek( Self:nfHandle , 0 , FS_SET ) Self:nFileSize := ReadFile( @Self:aLines , @Self:nfHandle , @Self:nBufferSize , @Self:nFileSize , @Self:cCRLF ) Self:ft_fGoTop() CATCHEXCEPTION Self:nfHandle := -1 ENDEXCEPTION Return( Self:nfHandle ) /*/ Funcao: ReadFile Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Percorre o Arquivo a ser lido e alimento o Array aLines Sintaxe: ReadFile( aLines , nfHandle , nBufferSize , nFileSize , cCRLF ) : nLines Read /*/ Static Function ReadFile( aLines , nfHandle , nBufferSize , nFileSize , cCRLF ) Local cLine := "" Local cBuffer := "" Local nLines := 0 Local nAtPlus := ( Len( cCRLF ) -1 ) Local nBytesRead := 0 While ( nBytesRead <= nFileSize ) cBuffer += fReadStr( @nfHandle , @nBufferSize ) nBytesRead += nBufferSize While ( cCRLF $ cBuffer ) ++nLines cLine := SubStr( cBuffer , 1 , ( AT( cCRLF , cBuffer ) + nAtPlus ) ) cBuffer := SubStr( cBuffer , Len( cLine ) + 1 ) cLine := StrTran( cLine , cCRLF , "" ) aAdd( aLines , cLine ) cLine := "" End While End While IF !Empty( cBuffer ) ++nLines aAdd( aLines , cBuffer ) cBuffer := "" EndIF Return( nLines ) /*/ METHOD: ft_fClose Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Fechar o Arquivo aberto pela ft_fOpen ou ft_fUse Sintaxe: ft():ft_fClose() : NIL /*/ METHOD ft_fClose() CLASS fT IF ( Self:nfHandle > 0 ) fClose( Self:nfHandle ) EndIF aSize( Self:aLines , 0 ) Self:cFile := "" Self:cLine := "" Self:nRecno := 0 Self:nfHandle := -1 Self:nFileSize := 0 Self:nLastRecno := 0 Return( NIL ) /*/ METHOD: ft_fAlias Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Retornar o Nome do Arquivo Atualmente Aberto Sintaxe: ft():ft_fAlias() : cFile /*/ METHOD ft_fAlias() CLASS fT Return( Self:cFile ) /*/ METHOD: ft_fExists Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Verifica se o Arquivo Existe Sintaxe: ft():ft_fExists( cFile ) : lExists /*/ METHOD ft_fExists( cFile ) CLASS fT Local lExists TRYEXCEPTION IF Empty( cFile ) BREAK EndIF lExists := File( cFile ) CATCHEXCEPTION lExists := .F. ENDEXCEPTION Return( lExists ) /*/ METHOD: ft_fRecno Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Retorna o Recno Atual Sintaxe: ft():ft_fRecno() : nRecno /*/ METHOD ft_fRecno() CLASS fT Return( Self:nRecno ) /*/ METHOD: ft_fSkip Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Salta n Posicoes Sintaxe: ft():ft_fSkip( nSkipper ) : nRecno /*/ METHOD ft_fSkip( nSkipper ) CLASS fT DEFAULT nSkipper := 1 Self:nRecno += nSkipper Return( Self:nRecno ) /*/ METHOD: ft_fGoTo Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Salta para o Registro informando em nGoto Sintaxe: ft():ft_fGoTo( nGoTo ) : nRecno /*/ METHOD ft_fGoTo( nGoTo ) CLASS fT Self:nRecno := nGoTo Return( Self:nRecno ) /*/ METHOD: ft_fGoTop Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Salta para o Inicio do Arquivo Sintaxe: ft():ft_fGoTo( nGoTo ) : nRecno /*/ METHOD ft_fGoTop() CLASS fT Return( Self:ft_fGoTo( 1 ) ) /*/ METHOD: ft_fGoBottom Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Salta para o Final do Arquivo Sintaxe: ft():ft_fGoBottom() : nRecno /*/ METHOD ft_fGoBottom() CLASS fT Return( Self:ft_fGoTo( Self:nFileSize ) ) /*/ METHOD: ft_fLastRec Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Retorna o Numero de Registro do Arquivo Sintaxe: ft():ft_fLastRec() : nRecCount /*/ METHOD ft_fLastRec() CLASS fT Return( Self:nFileSize ) /*/ METHOD: ft_fRecCount Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Retorna o Numero de Registro do Arquivo Sintaxe: ft():ft_fRecCount() : nRecCount /*/ METHOD ft_fRecCount() CLASS fT Return( Self:nFileSize ) /*/ METHOD: ft_fEof Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Verifica se Atingiu o Final do Arquivo Sintaxe: ft():ft_fEof() : lEof /*/ METHOD ft_fEof() CLASS fT Return( Self:nRecno > Self:nFileSize ) /*/ METHOD: ft_fBof Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Verifica se Atingiu o Inicio do Arquivo Sintaxe: ft():ft_fBof() : lBof /*/ METHOD ft_fBof() CLASS fT Return( Self:nRecno < 1 ) /*/ METHOD: ft_fReadLine Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Le a Linha do Registro Atualmente Posicionado Sintaxe: ft():ft_fReadLine() : cLine /*/ METHOD ft_fReadLine() CLASS fT TRYEXCEPTION Self:nLastRecno := Self:nRecno Self:cLine := Self:aLines[ Self:nRecno ] CATCHEXCEPTION Self:cLine := "" ENDEXCEPTION Return( Self:cLine ) /*/ METHOD: ft_fReadLn Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Le a Linha do Registro Atualmente Posicionado Sintaxe: ft():ft_fReadLn() : cLine /*/ METHOD ft_fReadLn() CLASS fT Return( Self:ft_fReadLine() ) /*/ METHOD: ft_fError Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Retorna o Ultimo erro ocorrido Sintaxe: ft():ft_fError( @cError ) : nDosError /*/ METHOD ft_fError( cError ) CLASS fT cError := CaptureError() Return( fError() ) /*/ METHOD: ft_fSetBufferSize Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Redefine nBufferSize Sintaxe: ft():ft_fSetBufferSize( nBufferSize ) : nLastBufferSize /*/ METHOD ft_fSetBufferSize( nBufferSize ) CLASS fT Local nLastBufferSize := Self:nBufferSize DEFAULT nBufferSize := 1024 Self:nBufferSize := nBufferSize Self:nBufferSize := Max( Self:nBufferSize , 1 ) Return( nLastBufferSize ) /*/ METHOD: ft_fSetCRLF Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Redefine cCRLF Sintaxe: ft():ft_fSetCRLF( cCRLF ) : nLastCRLF /*/ METHOD ft_fSetCRLF( cCRLF ) CLASS fT Local cLastCRLF := Self:cCRLF DEFAULT cCRLF := CRLF Self:cCRLF := cCRLF Return( cLastCRLF )
Para baixar o código da classe, do exemplo e dos arquivos usados, clique aqui. []s иαldσ dj
#INCLUDE "PROTHEUS.CH" /*/ Funcao: FTFSample Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Exemplo de Uso da Classe fT /*/ User Function FTFSample() Local aCab Local aDet Local cFile := "fTfSample.csv" //Deve estar em \system\ aFile := FileToArr( @cFile ) aCab := aFile[1] aDet := aFile[2] Return( NIL ) /*/ Funcao: FileToArr Autor: Marinaldo de Jesus Data: 01/05/2011 Descricao: Exemplo de Uso da Classe fT /*/ Static Function FileToArr( cFile ) Local aCab := {} Local aDet := {} Local cLine := "" Local cToken := Chr(255) Local oFT := fT():New() BEGIN SEQUENCE IF ( oFT:ft_fUse( cFile ) <= 0 ) BREAK EndIF While !( oFT:ft_fEof() ) IncProc() cLine := oFT:ft_fReadLn() ConOut( cLine ) cLine := StrTran( cLine , '""' , '" "' ) //Carrego um espaço em branco cLine := StrTran( cLine , '","' , cToken ) //Defino o Separador cLine := StrTran( cLine , '"' , "" ) //Retiro as Aspas IF ( oFT:ft_fRecno() == 1 ) aCab := StrTokArr( cLine , cToken ) //A primeira Linha contem o Cabeçalho dos campos Else aAdd( aDet , StrTokArr( cLine , cToken ) ) //As demais linhas sao os Detalhes EndIF cLine := "" oFT:ft_fSkip() End While oFT:ft_fUse() END SEQUENCE Return( { aCab , aDet } )
EXCELENTE !!!
ResponderExcluirGostaria de saber se o arquivo que estou lendo precisa estar dentro do protheus_data?
ResponderExcluirNão necessariamente.
ExcluirMano você é monstro, parabéns!
ResponderExcluir