• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Psycop

Problema com abertura de ficheiro txt

49 posts in this topic

Boas

Estou a tentar abrir um ficheiro txt que contem a seguinte informação:

sessao 0

totais 0

Apenas é esta a informação que esta no ficheiro, o que acontece é que não estou a conseguir ler correctamente as strings sessão e totais.

Estou a programar usando o codeblocks e Linux.

Aqui fica o pedaço de código responsável pela leitura do ficheiro:

printf("\t\t\t*Estatisticas Totais do Jogo*\n\n\n");
                            FILE *entrada;
                            char tipo[100];
                            int valor;

                            //Abrir o Ficheiro

                            entrada = fopen("//home/nuno//Dropbox//Projectos em C//Jogo do Galo", "r");

                            if (entrada == NULL)
                            {
                                printf("Erro na Abretura do Ficheiro:\n");
                                getchar();
                            }

                            while(entrada != EOF)
                            {
                                fscanf(entrada,"%s %d",tipo, &valor);
                                printf("%s = %d\n", tipo, valor);
                                break;
                            }

                            fclose(entrada);
                            break;

Não consigo entender onde está o erro uma vez que o output é o seguinte:

(espaço que seria para a string ) = 0
.

Alguém sabe o que estou a fazer de mal?

Cumps

0

Share this post


Link to post
Share on other sites

entrada é um ponteiro; EOF é um inteiro: nao os podes comparar directamente.

Sugestao: aumenta o nivel de warnings do teu compilador e faz compilacoes limpas, sem erros, claro! nem warnings.

Outra coisa: o scanf é perigoso para buffer overflows. Para o tornares seguro limita o numero de caracteres a ler na especificacao do formato

char tipo[100];
fscanf(entrada, "%99s %d", tipo, &valor);

Verifica sempre o resultado do scanf!

Com duas variaveis a atribuir o resultado devia ser 2; qulquer outra coisa é erro;

if (fscanf(entrada, "%99s%d", tipo, &valor) != 2) /* erro no scanf */;

Em vez de /* erro no scanf */ mostra uma mensagem e aborta ...

Tirando isto parece-me que o programa devia funcionar.

0

Share this post


Link to post
Share on other sites

Olá

Experimentei com as dicas que me indicaste e o retorno que tenho é um erro no fscanf, ou seja o fscan não está a ler os dois parâmetros.

Agora assim:

FILE *entrada;
                            char tipo[100];
                            int valor;

                            //Abrir o Ficheiro

                            entrada = fopen("//home/nuno//Dropbox//Projectos em C//Jogo do Galo", "r");

                            if (entrada == NULL)
                            {
                                printf("Erro na Abretura do Ficheiro:\n");
                                getchar();
                            }

                            while(fscanf(entrada,"%99s %d",tipo, &valor) != EOF)
                            {

                                if(fscanf(entrada,"%99s %d",tipo, &valor) != 2)
                                {
                                    printf("Erro de Leitura");
                                    break;
                                }
                                else
                                {
                                    printf("%s = %d\n", tipo, valor);
                                    break;
                                }
                            }

                            fclose(entrada);
                            break;

Ao compilar não tenho qualquer warning relativo a esta situação, mas continua a não aparecer a apresentação das palavras "sessão" e "totais".

Não consigo mesmo entender o porque...

Cumps

0

Share this post


Link to post
Share on other sites

Definição: Espaço branco = espaço, '\t' ou '\n'.

Quando testas a condição no início do ciclo 'while' tentas ler do ficheiro até 99 caracteres ou até encontrar espaço branco, depois zero ou mais espaços brancos e depois um número inteiro. Tudo isso pode ser carregado.

Mas uma linha de ficheiro de texto é terminada com um '\n' (em Linux). Quando tentas carregar a segunda linha o 'fscanf' vai encontrar isso e não os caracteres que espera e falha.

Para resolver come o '\n' no fim de cada linha com:

fscanf(entrada,"%99s %d ",tipo, &valor)
                       ^------ Espaço aqui

0

Share this post


Link to post
Share on other sites

Agora tens 2 fscanf seguidos (um no while, outro no if). Se o teu programa funcionasse so iria apresentar a linha com "totais 0"; a linha com "sessao 0" teria sido 'comida' no while.

Verifica qual é o valor que o fscanf devolve ...

while (1) {
    int chk = fscanf(entrada, "%99s%d", tipo, &valor);
    printf("o fscanf devolveu %d.\n", chk);
    /* ... break algures ... */
}


fscanf(entrada,"%99s %d ",tipo, &valor)
                       ^------ Espaço aqui

No loop a seguir, o "%99s" 'come' os espacos que o teu espaço pretende comer.

Ter, "%99s %d" e "%99s%d" é absolutamente igual: no primeiro caso os espaços sao ignorados por causa do espaço na string de conversao (e o "%d" começa logo com coisas diferentes de espaço); no segundo caso os espaços sao ignorados porque o "%d" ignora espaços.

0

Share this post


Link to post
Share on other sites

Correndo isto o printf devolve o valor "-1". Coisa que não esta dentro do ficheiro...

Cumps

Agora tens 2 fscanf seguidos (um no while, outro no if). Se o teu programa funcionasse so iria apresentar a linha com "totais 0"; a linha com "sessao 0" teria sido 'comida' no while.

Verifica qual é o valor que o fscanf devolve ...

while (1) {
    int chk = fscanf(entrada, "%99s%d", tipo, &valor);
    printf("o fscanf devolveu %d.\n", chk);
    /* ... break algures ... */
}

0

Share this post


Link to post
Share on other sites

No loop a seguir, o "%99s" 'come' os espacos que o teu espaço pretende comer.

Tens razão, mas de qualquer maneira acho preferível consumir toda a linha de uma vez.

Já agora, para referência futura e corrige-me se estiver enganado: todos os identificadores, com a excepção do '%c', ignoram espaço branco até que encontrem um caracter válido para eles. Só depois o espaço branco é considerado um terminador.

0

Share this post


Link to post
Share on other sites

Correndo isto o printf devolve o valor "-1". Coisa que não esta dentro do ficheiro...

O -1 é o sinal que o ficheiro nao tem mais dados (normalmente escreve-se EOF). É a unica maneira do scnaf devolver um numero negativo.


Já agora, para referência futura e corrige-me se estiver enganado: todos os identificadores, com a excepção do '%c', ignoram espaço branco até que encontrem um caracter válido para eles. Só depois o espaço branco é considerado um terminador.

um caracter válido ... on inválido. Se for válido o scanf faz a conversao; se for inválido ele pára deixando esse caracter 'pendurado'.

Os conversores que nao ignoram espacos sao o "%c" e o "%[...]".

0

Share this post


Link to post
Share on other sites

Já agora, o ficheiro foi criado em Linux ou em Windows ? As linhas dos ficheiros criados em Linux terminam com '\n' mas os criados em Windows terminam com '\r' + '\n'. Sendo o teu programa compilado em Linux julgo que o fscanf não considera o '\r' como um espaço branco.

0

Share this post


Link to post
Share on other sites

Um "espaço branco" é um dos caracteres para os quais a funcao isspace(), declarada em <ctype.h> devolve "TRUE". Normalmente, nos locales "C" ou "POSIX" esses caracteres sao '\f' (form-feed), '\n' (newline), '\r' (carriage return), '\t' (horizontal tab), e '\v' (vertical tab) e o espaco, claro.

0

Share this post


Link to post
Share on other sites

Boas

Foi tudo criado em linux.

O ficheiro foi com o gedit.

Cumps

0

Share this post


Link to post
Share on other sites

sessao 0

está na primeira linha do ficheiro? se tiveres um \n pode estar a falhar devido a isso (embora eu ache que devia retornar 1). Para saber mais acerca do erro podes tentar algo como:

while (1) {
    int chk = fscanf(entrada, "%99s%d", tipo, &valor);
    perror("resultado fscanf:");
    printf("o fscanf devolveu %d.\n", chk);
    /* ... break algures ... */
}

0

Share this post


Link to post
Share on other sites

Boas

Estou mesmo perdido com esta situação. Alterei o ficheiro para a seguinte forma só para testar:

0

Apenas o Zero na primeira linha do ficheiro, sem espaços antes,

E usando este código:

case 2:
                        {
                            printf("\t\t\t*Estatisticas Totais do Jogo*\n\n\n");

                            FILE *entrada;
                            int sessao, totais;

                            //Abrir o Ficheiro

                            entrada = fopen("//home/nuno//Dropbox//Projectos em C//Jogo do Galo", "r");

                            if (entrada == NULL)
                            {
                                printf("Erro na Abretura do Ficheiro:\n");
                                getchar();
                            }

                        while(!feof(entrada))
                        {
                            fscanf(entrada,"%d",&sessao);
                            printf("%d", sessao);
                            break;
                        }

                            fclose(entrada);
                            break;
                        }

Mesmo assim não consigo ler o conteúdo do ficheiro e apresenta-lo, tendo o 1 no ficheiro o que me é apresentado no programa é o valor zero.

0

Share this post


Link to post
Share on other sites

                            FILE *entrada;
                            //Abrir o Ficheiro
                            entrada = fopen("//home/nuno//Dropbox//Projectos em C//Jogo do Galo", "r");
                            if (entrada == NULL)
                            {
                                printf("Erro na Abretura do Ficheiro:\n");
                                getchar();
                            }

Tens a certeza que o nome esta bem? em vejo no meio do nome uma quebra de linha ...

De qualquer maneira, se houver problemas na abertura do ficheiro o programa continua normalmente como se estivesse tudo bem.

Experimenta sair do programa em vez de esperar por uma tecla.

Ja agora podes tambem imprimir uma mensagem melhorzita, que explica qual o erro em vez de apenas dizer que houve erro

if (entrada == NULL) {
    perror("entrada");
    exit(EXIT_FAILURE); /* nao te esquecas de #include <stdlib.h> */
}

                        while(!feof(entrada))
                        {
                            fscanf(entrada,"%d",&sessao);
                            printf("%d", sessao);
                            break;
                        }

Verifica o valor devolvido pelo fscanf em vez de usares o feof(). O feof() serve para averiguar se o ultimo erro que ocorreu se deveu ao ficheiro ter chegado ao fim. Em particular, se nao tiver ocorrido um erro, o feof() devolve sempre falso. O fscanf verifica que houve erro antes.

while (fscanf(entrada, "%d", &sessao) == 1) { /* ... */ }
/* quando a execucao chega aqui, ocorreu um erro no fscanf(),
** se quiseres averiguar porque, podes usar o feof() */
fclose(entrada);

0

Share this post


Link to post
Share on other sites

Verifiquei a situação do nome e se retirar os espaços surge-me então a mensagem de erro na abertura do ficheiro e "Segmentation fault".

Se voltar a colocar os espaços, não dá erro mas continua a retornar apenas o valor zero...

Utilizando

while (fscanf(entrada, "%d", &sessao) == 1)

nem sequer é impresso qualquer valor no ecrã!

Cumps

0

Share this post


Link to post
Share on other sites

Olha ... mete o nome do ficheiro numa variavel, e imprime essa variavel antes de abrir o ficheiro.

char nomeficheiro[] = "//home/bla bla bla/Jogo do Galo";
printf("A abrir o ficheiro '%s' ...\n", nomeficheiro);
entrada = fopen(nomeficheiro, "r");

0

Share this post


Link to post
Share on other sites

Implementando desta forma apena é impresso o nome do ficheiro, nada mais....

case 2:
                        {
                            printf("\t\t\t*Estatisticas Totais do Jogo*\n\n\n");

                            FILE *entrada;
                            int sessao, totais;

                            char nomeficheiro[] = "//home/nuno//Dropbox//Projectos em C//Jogo do Galo";
                            printf("A abrir o ficheiro '%s' ... \n", nomeficheiro);

                            //Abrir o Ficheiro

                            entrada = fopen(nomeficheiro, "r");

                            if (entrada == NULL)
                            {
                                printf("Erro na Abretura do Ficheiro:\n");
                                getchar();
                            }

                        while(fscanf(entrada, "%d", &sessao) == 1)
                        {
                            printf("%d", sessao);
                            break;
                        }

                            fclose(entrada);
                            break;
                        }

Cumps

0

Share this post


Link to post
Share on other sites

Eu estava a confundir as barras no nome do ficheiro com as barras ao contrario ... mas acho estranho estarem duas ou mais seguidas. Normalmente ve-se /home/nuno/Dropbox/Projects em C/etc :-)

Verifica o conteudo do ficheiro com um examinador hexadecimal, por exemplo

hd '/home/nuno/.../Jogo do Galo'

Se nao tiveres um utilitario que funcione podes usar o teu proprio programa, mas le caracter a caracter (com fgetc()) em vez de usares scanf()

int ch;
fopen();
while ((ch = fgetc(entrada)) != EOF) {
    printf("valor lido: %d (caracter '%c')\n", ch, ch);
}
fclose();

0

Share this post


Link to post
Share on other sites

As directorias só tem apenas uma \, mas o que aprendi e pelo que tenho lido colocam-se duas \\ devido a apenas representar um caracter.

Quanto ao directorio retirei-o directamente das propriedades do ficheiro de texto.

Não sei mesmo o que possa estar a acontecer...

0

Share this post


Link to post
Share on other sites

A barra normal / usa-se em Unix.

A barra invertida \ usa-se em Windows.

Dentro do codigo fonte em C, dentro duma string literal, usa-se a barra invertida tambem para especificar "caracteres especiais", por exemplo o tab "\t". Para especificar um t a seguir a uma barra invertida tem-se de duplicar a barra invertida "\\t". A mesma logica aplica-se aos nomes de ficheiros.

Mas, mesmo em Windows, o teu programa deve funcionar com barras normais nos nomes de ficheiros.

As duas expressoes abaixo deviam funcionar exactamente da mesma forma

fopen("C:/DOS/AUTOEXEC.BAT", "r")

fopen("C:\\DOS\\AUTOEXEC.BAT", "r") /* hehe, o GeSHi atrapalha-se todo */

Se estas em Windows, provavelmente tens um BOM no ficheiro.

0

Share this post


Link to post
Share on other sites

Se estas em Windows, provavelmente tens um BOM no ficheiro.

Estou em Linux e criei o ficheiro com o gedit.

Cumps

0

Share this post


Link to post
Share on other sites

O gedit pode manter o BOM no ficheiro. O BOM esta la e nunca o ves.

Experimenta

hexdump -C ficheiro
file ficheiro
wc -c ficheiro

0

Share this post


Link to post
Share on other sites

Bem, não sei qual era o problema, o que acontece é que apaguei o ficheiro txt e criei um novo com a seguinte configuração:

Sessão 1 Totais 2

E usando o seguinte código já consigo efectuar a leitura correctamente.

printf("\t\t\t*Estatisticas Totais do Jogo*\n\n\n");

                            FILE *entrada;
                            int sessao, totais;
                            char tiposessao[10], tipototais[10];

                            char nomeficheiro[] = "//home/nuno//Dropbox//Projectos em C//Jogo do Galo//EstatisticasTotais";

                            //Abrir o Ficheiro

                            entrada = fopen(nomeficheiro, "r");

                            if (entrada == NULL)
                            {
                                printf("Erro na Abretura do Ficheiro:\n");
                                getchar();
                            }

                        while(fscanf(entrada, "%s %d\t%s %d", tiposessao, &sessao, tipototais, &totais) != EOF)
                        {
                            printf("%s %d \n", tiposessao, sessao);
                            printf("%s %d \n", tipototais, totais);
                            break;
                        }

                            fclose(entrada);
                            break;

0

Share this post


Link to post
Share on other sites

Bem, não sei qual era o problema,

O problema era o BOM.

0

Share this post


Link to post
Share on other sites

O problema era o BOM.

Então esse problema é algo importante de se saber certo? Existem maneiras de se contornar isso?

Já agora como devem ter percebido eu vou usar o ficheiro txt para guardar a informação de umas estatísticas, que serão actualizadas cada vez que o programa corre, é possível substituir a informação que necessito apenas?

Já pesquisei sobre o modo "a", "r+" "w+" e "a+" mas não sei qual o mais adequado. Suponho que seja o "r+", alguma opinião?

Cumps

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now