Você está na página 1de 66

MEGATPICOMANIPULAODEARQUIVOSEDIRETRIOS

Ambiente: Opensuse 11.1 , kernel 2.6.27, gcc 4.3.2. Com a inteno de evitar mais posts com perguntas "como leio do arquivo?" e similares (mas duvidando que vo usar a busca do frum), resolvi escrever este post gigantesco com algumas operaes comuns envolvendo arquivos e diretrios. Mas antes de comear, preciso ter "material" para testar os cdigos. O seguinte script (Python 2.6) cria arquivos com contedo aleatrio no diretrio atual (note que necessrio criar o diretrio manualmente).

Cdigo #1
#!/usr/bin/python #coding=utf-8 from random import randint,choice from string import letters, printable QTDE_ARQUIVOS = input("Digite a quantidade de arquivos a ser criada: ") TAM_MAXIMO= input("Digite o tamanho mximo (em bytes) do arquivo: ") TAM_NOME = input("Digite o tamanho mximo para os nomes dos arquivos: ") for i in range(0,QTDE_ARQUIVOS): data_qtd = randint(0,TAM_MAXIMO) nome = ''.join([choice(letters) for X in xrange(TAM_NOME)]) data = ''.join([choice(printable) for Y in xrange(data_qtd)]) with open(nome,"w") as arquivo: arquivo.writelines(data)

TPICOS
1. Abertura de Arquivos 2. Acesso Aleatrio 3. Leitura de Arquivo 4. Escrita em Arquivo 5. Criar Arquivo 6. Remover Arquivo 7. Renomear Arquivo 8. Obter Informaes Sobre um Arquivo 9. Arquivos Temporrios 10. Criar Diretrios 11. Ler Diretrios 12. File-Tree Walk 13. Remover Diretrios 14. Outras Operaes com Diretrios

ABERTURA DE ARQUIVOS
O primeiro passo para se fazer alguma coisa mais interessante abrir o arquivo. Aps executar o script anterior, o diretrio contm os seguintes arquivos:

Criao dos arquivos (cdigo #01) O contedo deles no muito legvel, mas vamos em frente. Para abrir um arquivo utilizamos a funo fopen do header stdio.h. Para fechar um arquivo aberto, utilizamos a funo fclose. Inicialmente no vamos realizar nenhuma outra operao a no ser essas duas. O prottipo da funo fopen pede um segundo argumento que especifica o modo de abertura do arquivo: r : somente leitura. r+ : leitura e escrita. w: somente escrita, sendo que o contedo do arquivo apagado. w+: somente escrita, sendo que o arquivo criado se no existir. Se o arquivo existir, seu contedo apagado. a: escrita somente, a partir do final do arquivo. Se no existir, o arquivo criado. a+: leitura e escrita, a partir do final do arquivo. Se no existir, o arquivo criado.

Escolhido um dos arquivos, seguem os primeiros cdigos.

Cdigo #2
#include <stdio.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("cwFH","r"); fclose(arquivo); return 0; }

Abertura de arquivo somente para leitura.

Se tentarmos abrir um arquivo que no existe para leitura ocorre uma falha de segmentao. Isso acontece ao tentarmos fechar o arquivo, j que fopen retorna NULL se o arquivo no existir e com fclose tentamos acessar um endereo e memria invlido. Ento, o primeiro teste que deve ser feito verificar se o arquivo existe no diretrio, utilizando o valor de retorno de fopen: caso seja NULL sabemos que o arquivo invlido (no confunda com arquivo corrompido). Em detalhes: seu programa um processo no sistema. Cada processo possui um espao de endereamento, que o intervalo entre o endereo A e B na memria que ele pode acessar, sendo que um processo no pode acessar o espao de endereamento de outro. Segmentao um modelo de gerenciamento e proteo de memria. O nome foi mantido, ento, mesmo que a arquitetura do sistema utilize memria paginada, o sistema retorna um aviso de falha de segmentao. Em sistemas UNIX, quando o processo acessa um endereo proibido o sinal SIGSEGV enviado ao processo. No Windows o processo recebe a exceo STATUS_ACCESS_VIOLATION (e uma telinha pedindo para o usurio enviar um relatrio Microsoft). Olhando nos defines da linguagem vemos que o NULL, em C, definido como 0 (execute um find . -name "*.h" -exec grep "#define NULL" --color \{\} \+ em /usr/lib/include), mas 0x000000 o primeiro endereo utilizado e est protegido, sendo que somente processos em kernel mode -- a grosso modo, um processo em kernel mode pode fazer tudo no sistema -- podem escrever nesses endereos. Independente de voc ser ou no o usurio root/Administrador do sistema, voc est em user mode em relao ao kernel (no confunda com permisses de arquivos. Estamos num nvel muito mais baixo que isso). Isso um mecanismo de proteo do sistema operacional. Como voc no tem permisso de alterar o contedo desse endereo (e nem de ler), o sistema operacional retorna esse erro.

Falha de segmentao.

A explicao acima simplista e deixei de entrar em detalhes sobre outros tpicos de sistemas operacionais e arquitetura de computadores. Para mais informaes leia "Computer Organization & Design: The Hardware/Software Interface" (D. A. Patterson e J. L. Hennessy), "Arquitetura e Organizao de Computadores" (William Stallings), "Sistemas Operacionais - Conceitos" (Abraham Silberschatz, Peter Galvin,Greg Gagne) ,"Operating Systems - Internals and Design Principles" (William Stallings) , "Modern Operating Systems" (A. S. Tanenbaum) e "Understanding the Linux Kernel" (Marco Cesati, Daniel Bovet). NOTA: Falha de segmentao tambm pode ser causada por um stack overflow, em funes recursivas que no retornam. Mas o problema o mesmo: voc est acessando um endereo que no pode.

Cdigo #3
#include <stdio.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("---","r"); if (arquivo != NULL) fclose(arquivo); return 0; }

Leitura de arquivo inexistente. Retornando ao cdigo que gera falha de segmentao: uma coisa que no luxo retornar mensagens informando ao usurio (e a voc mesmo) o que deu errado. Normalmente usa-se defines ou strings constantes que carregam uma mensagem e os printfs e puts pipocam pelo cdigo fazendo referncia a uns 50 defines:

Cdigo #4
#include <stdio.h> #define MSG001 "No foi possvel abrir o arquivo.\n" int main (int argc, char *argv[]) { FILE * arquivo = fopen("novo","r"); if (arquivo == NULL) { printf("%s",MSG001); return 1; } fclose(arquivo); return 0; }

Informar erros atravs de defines. Esse tipo de abordagem desnecessria. Quanto maior o cdigo, mais mensagens vo se acumulando. E o pior: nunca se consegue prever todas as condies passveis de erro. O modo mais curto ("Work smarter, not harder") utilizar a varivel errno, definida em errno.h. Quando algo d errado na abertura de um arquivo essa varivel automaticamente definida com um valor (existem umas 20 macros possveis). Certamente uma prtica a ser adquirida em favor da sanidade do programador e da economia de tempo, afinal voc tem que se preocupar em fazer as coisas funcionarem, e no em adivinhar que situaes catastrficas podem existir.

Cdigo #5
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("novo","r"); if (arquivo == NULL) { printf("%m\n"); return 1; } fclose(arquivo); return 0; }

Informar erros atravs de errno.

Sada do cdigo #5

Cdigo #6
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("novo","y"); if (arquivo == NULL) { printf("%m\n"); return 1; } fclose(arquivo); return 0; }

Indicar modo de abertura inexistente.

Sada do cdigo #6

Cdigo #7
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); int ch; if (!arquivo) { printf("%m\n"); return 1; } fclose(arquivo); return 0; }

Sada do cdigo #7. Leitura de arquivo sem permisso.

Algo comum de se ver , aps tentar abrir um arquivo que no existe, o programa utiliza uma funo especfica para criao de arquivos para solucionar a situao. Cdigo #8
#include <stdio.h> int main(int argc,char *argv[]) { FILE * arquivo = fopen("---","r"); if (arquivo == NULL) // instruo para criar arquivo //restante do programa fclose(arquivo); return 0; }

Nesse caso mais rpido utilizar o modo a+, mesmo que no seja utilizada a escrita.

Cdigo #9
#include <stdio.h> int main(int argc,char *argv[]) { FILE * arquivo = fopen("---","a+"); //restante do programa fclose(arquivo); return 0; }

Existe ainda um outro modo,b, de arquivo binrio, que pode ser utilizado em conjunto com qualquer dos outros modos j mencionados, mas serve somente para compatibilidade com o C89 e em sistemas que implementam o POSIX ele ignorado.

ACESSO ALEATRIO
Como o valor de retorno de fopen um endereo de memria, podemos nos movimentar "livremente" por ele utilizando aritmtica de ponteiros. As funes definidas em stdio.h que so utilizadas para isso so: int fseek(FILE *stream, long offset, int whence); Define o indicador de posio em arquivo como whence+offset(em bytes). O valor de whence pode ser SEEK_SET (incio do arquivo), SEEK_CUR (posio atual) ou SEEK_END (final do arquivo). long ftell(FILE *stream); Obtm o valor atual do indicador de posio do arquivo. void rewind(FILE *stream); Retorna o indicador de posio para o incio do arquivo. Equivalente a fseek(arquivo,-SEEK_CUR,SEEK_CUR) e fseek(arquivo,0L,SEEK_SET).

Cdigo #10
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); const long deslocamento = 16; const char string[] = "Posio atual no arquivo: %ld\n"; if (!arquivo) { printf("%m\n"); return 1; } // posio = 0 fseek(arquivo,deslocamento,SEEK_CUR); // posio = SEEK_CUR + 16 = 0 + 16 = 16 printf(string,ftell(arquivo)); rewind(arquivo); // posio = 0 fseek(arquivo,deslocamento,SEEK_SET); // posio = SEEK_SET + 16 = 0 + 16 = 16 printf(string,ftell(arquivo)); puts("==============================="); // O indicador est a 16 bytes do incio do arquivo. fseek(arquivo,-1*deslocamento,SEEK_CUR); printf(string,ftell(arquivo)); // posio = SEEK_CUR-16 = 16-16 = 0 fseek(arquivo,deslocamento,SEEK_SET); // posio = SEEK_SET + 16 = 16 fseek(arquivo,0,SEEK_SET); printf(string,ftell(arquivo)); // posio = SEEK_SET + 0 = 0 puts("==============================="); fseek(arquivo,deslocamento,SEEK_SET); // posio = 16

fseek(arquivo,-1*deslocamento,SEEK_CUR); // posio = SEEK_CUR - 16 = 16 - 16 = 0 printf(string,ftell(arquivo)); fseek(arquivo,deslocamento,SEEK_SET); // posio = SEEK_SET + 16 = 0 + 16 =16 fseek(arquivo,0,SEEK_SET); // posio = SEEK_SET + 0 = 0 + 0 = 0 printf(string,ftell(arquivo)); fclose(arquivo); return 0;

int fgetpos(FILE *stream, fpos_t *pos); Retorna a posio atual no arquivo, armazenando em *pos.

int fsetpos(FILE *stream, fpos_t *pos); Define a posio no arquivo de acordo com *pos. Note que as posies indicadas em fsetpos so absolutas (ex: "o 42 byte do arquivo") e as posies indicadas por fseek so relativas. O que acontece com os seguintes cdigos? Cdigo #11
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); if (!arquivo) { printf("%m\n"); return 1; } fseek(arquivo,999999999,SEEK_END); fclose(arquivo); return 0;

Cdigo #12
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); if (!arquivo) { printf("%m\n"); return 1; } fseek(arquivo,999999999999,SEEK_END); fclose(arquivo); return 0; }

Cdigo #13
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); if (!arquivo) { printf("%m\n"); return 1; } fseek(arquivo,-999999999,SEEK_SET); fclose(arquivo); return 0;

No primeiro cdigo estamos acessando uma posio alm do final do arquivo. Aparentemente, isso est errado, mas a funo executa corretamente. Estamos lidando com memria e no com indicadores de trmino de arquivo (EOF). No segundo cdigo, a funo retorna 1, indicando que ocorreu um erro: o segundo argumento invlido. Podemos ver isso em tempo de compilao.

Sada
isis@linux-8ogs:~/src/C/Imasters/MEGA-1> gcc -g arquivos002.c arquivos002.c: In function main: arquivos002.c:12: warning: integer constant is too large for long type arquivos002.c:12: warning: overflow in implicit constant conversion

Mesmo se colocarmos um valor que esteja dentro do limite do tipo long, mas que seja negativo, o erro retornado ser EINVAL.

LEITURA DE ARQUIVO
Aqui podemos escolher entre fgetc (leitura caractere a caractere), fgets (leitura linha a linha), fread (leitura em blocos de bytes), fscanf (leitura formatada, como scanf) e getc. A funo fgetc l um caractere do arquivo como char sem sinal e realiza o cast para int, podendo retornar EOF.

Cdigo #14
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); if (!arquivo) { printf("%m\n"); return 1; } while (1) { printf("%c\n",fgetc(arquivo)); } fclose(arquivo); return 0;

Nesse cdigo temos um loop infinito. Podemos verificar se chegamos no final do arquivo. Uma soluo pode ser essa:

Cdigo #15
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); int ch; if (!arquivo) { printf("%m\n"); return 1; } while((ch=fgetc(arquivo)) != EOF) { printf("%c\n", ch); } printf("%m\n"); fclose(arquivo); return 0;

Repare que a sada do ltimo printf "Success". Como saber o que eventualmente deu errado numa leitura? Precisamos verificar o indicador de erro para o arquivo. Para isso usamos a funo ferror. Esta funo retorna 0 se o indicador est definido. No adianta olhar em errno, j que ela no atribui valor nenhum a essa varivel. Experimente trocar int ch por char ch. Voc deve ter tido sucesso na leitura, mas o manual da funo diz: QUOTE MAN FGETC
Se o valor inteiro retornado por fgetc() for armazenado em uma varivel e ento comparado com a constante inteira EOF, a comparao pode nunca ser bem-sucedida. (...) As funes ferror() ou feof() devem ser utilizadas para diferenciar entre uma condio de erro e de final de arquivo.

A leitura caractere por caractere lenta. Dependendo do que voc est fazendo, ler linhas inteiras melhor. Para isso utiliza-se a funo fgets, que l n-1 bytes ou at que um \n seja encontrado. Se o final do arquivo for encontrado o indicador correspondente definido e fgets retorna NULL. No caso de um erro de leitura, o retorno tambm NULL, e o indicador de erro para o arquivo definido, alm da varivel errno.

Cdigo #16
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); char buffer[255]; if (!arquivo) { printf("%m\n"); return 1; } while(fgets(buffer,255,arquivo) != NULL) { printf("%s\n", buffer); } fclose(arquivo); return 0; }

Sada do cdigo #16.

O erro mais comum quando se usa essa funo na comparao de strings: o usurio digita a palavra, que comparada com a palavra lida do arquivo, resultando em false. Isso acontece porque o fgets inclui o \n existente no arquivo. Para elimin-lo, utilizamos a funo strchr (definida em string.h), que realiza a busca pela primeira ocorrncia do caractere C numa string S, retornando um ponteiro para a string.

Cdigo #17
#include <stdio.h> #include <errno.h> #include <string.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); char buffer[255]; if (!arquivo) { printf("%m\n"); return 1; } while(fgets(buffer,255,arquivo) != NULL) { (*strchr(buffer,'\n')) = '\0'; printf("%s\n", buffer); } fclose(arquivo); return 0; }

Executando o cdigo acima temos novamente uma falha de segmentao, porque a strchr no encontrou nenhum \n na string lida, retornando NULL. O motivo que o tamanho do buffer menor do que o comprimento das linhas.Se aumentarmos o tamanho do buffer para 500, por exemplo, o programa executa normalmente. Fgets tambm retorna NULL para final de arquivo quando no consegue ler nenhum caractere e em caso de erro na leitura define a varivel errno.

Sada aps aumentar o tamanho do buffer.

Para mais informaes e exemplos sobre fgets veja Why it's bad to use feof() to control a loop. Fread mais flexvel: como opera com limites em bytes, pode ser utilzada tanto para leitura caractere por caractere como para leitura de linhas inteiras, supondo que voc saiba o tamanho da maior linha do arquivo, j que ela no trabalha com o \n como marcador de final de leitura. Ela usa a fgetc quantas vezes forem especificadas no terceiro argumento. Seu valor de retorno a quantidade de elementos lidos, que somente menor do que o especificado no terceiro argumento se acontecer algum erro na leitura (define errno) ou se EOF for encontrado.

Cdigo #18
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("xWYT","r"); char buffer[2]; if (!arquivo) { printf("%m\n"); return 1; } while(fread(buffer,sizeof(char),1,arquivo) == 1) { printf("%c\n", buffer[0]); } fclose(arquivo); return 0; }

O problema que um tanto difcil usar essa funo corretamente sem que certos parmetros sejam fixos. Execute os prximos cdigos num arquivo com as seguintes linhas:

ARQUIVO
1234567890 qweasdzxc rty 5

Cdigo #19
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("teste","r"); char buffer[30]; if (!arquivo) { printf("%m\n"); return 1; } while(fread(buffer,sizeof(char),30,arquivo) == 30) { printf("%s\n", buffer); } fclose(arquivo); return 0;

Cdigo #20
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("teste","r"); char buffer[30]; if (!arquivo) { printf("%m\n"); return 1; } while(fread(buffer,sizeof(char),30,arquivo) < 30) { printf("%s\n", buffer); } fclose(arquivo); return 0; }

O primeiro cdigo no imprime nada porque a igualdade no foi satisfeita e o segundo fica em loop infinito porque no detectamos o final de arquivo, o que acontece tambm se trocarmos o < por <=. Acompanhe:

Cdigo #21
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("teste","r"); char buffer[50]; if (!arquivo) { printf("%m\n"); return 1; } while(fread(buffer,sizeof(char),50,arquivo) <= 50) { printf("%s\n", buffer); if (feof(arquivo)) break; } fclose(arquivo); return 0;

Sada do cdigo #21.

Conseguimos interromper o loop infinito, mas em compensao temos uma string estranha no final da impresso, pois ultrapassamos o final do arquivo. No adianta tentar (*strchr(buffer,EOF)) = '\0' antes do printf, pois resulta em falha de segmentao, j que EOF no um char e nem um valor existente (marcado) no final do arquivo (veja Definition of EOF and how to use it effectively). Uma forma que encontrei para contornar isso (alm de no usar a funo) utilizar a funo stat para determinar o tamanho do arquivo.

Cdigo #22
#include <stdio.h> #include <errno.h> #include <sys/stat.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("teste","r"); char buffer[50]; struct stat info; if (!arquivo) { printf("%m\n"); return 1; } stat("teste",&info); while(fread(buffer,sizeof(char),50,arquivo) <= 50) { buffer[info.st_size-1] = '\0'; printf("%s\n", buffer); } if (feof(arquivo)) break;

fclose(arquivo); return 0;

Sada do cdigo #22.

O problema quando o arquivo est vazio: falha de segmentao novamente. Para contornar esse problema devemos ter o seguinte cdigo:

Cdigo #23
#include <stdio.h> #include <errno.h> #include <sys/stat.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("teste","r"); char buffer[50]; struct stat info; if (!arquivo) { printf("%m\n"); return 1; } stat("teste",&info); while(fread(buffer,sizeof(char),50,arquivo) <= 50) { if (info.st_size) { buffer[info.st_size-1] = '\0'; printf("%s\n", buffer); } if (feof(arquivo)) break; } fclose(arquivo); return 0;

Sada do cdigo #22 em um arquivo vazio.

Sada do cdigo #23.

A ltima funo de leitura de arquivos fscanf. O prottipo parecido com o da funo scanf, mas o primeiro argumento o ponteiro para o arquivo. Vamos comear com esse cdigo:

Cdigo #24
#include <stdio.h> #include <errno.h> #include <string.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("teste","r"); char buffer[50]; char * endereco; if (!arquivo) { printf("%m\n"); return 1; } while(fscanf(arquivo,"%s",buffer) <= 50) { endereco = strrchr(buffer,'\n'); if (endereco) { *endereco = '\0'; printf("%s\n", buffer); } if (feof(arquivo)) break; } fclose(arquivo); return 0; }

No imprime nada, mas um printf("%m\n") fora do while retorna "Success". O valor de retorno de fscanf o nmero de combinaes bemsucedidas, que 0 no caso de erro. A funo retorna EOF se, antes da primeira falha de combinao ou converso, a entrada terminar. Experimente executar os dois cdigos a seguir com um arquivo contendo dados e outro vazio. A funo fscanf tambm define a varivel errno em caso de falha. Cdigo #25
#include <stdio.h> #include <errno.h> #include <string.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("teste","r"); char buffer[50]; if (!arquivo) { printf("%m\n"); return 1; } while(fscanf(arquivo,"%s",buffer) ) { printf("%s\n", buffer); if (feof(arquivo)) break; } fclose(arquivo); return 0;

Sada do cdigo #25.

Cdigo #26
#include <stdio.h> #include <errno.h> #include <string.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("teste","r"); char buffer[50]; if (!arquivo) { printf("%m\n"); return 1; } while(fscanf(arquivo,"%s",buffer) ) { if (feof(arquivo)) break; printf("%s\n", buffer); } fclose(arquivo); return 0;

Sada do cdigo #26.

A funo getc faz a mesma coisa que fgetc, mas segundo o manual, se a funo estiver definida como uma macro, pode tratar o stream incorretamente. O exemplo dado getc(*f++), sendo que o uso da funo deve ser precedido de "#undef getc".

ESCRITA EM ARQUIVO
Podemos escrever em arquivos utilizando 4 funes: fprintf, fputc, putc e fputs. A funo fprintf possui um prottipo semelhante ao da funo printf, mas com o arquivo (FILE *) especificado no primeiro argumento. O valor de retorno o nmero de bytes escritos e, em caso de erro, retorna um valor negativo, definindo errno.

Cdigo #27
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("novo","r"); if (!arquivo) { printf("%m\n"); return 1; } if (fprintf(arquivo,"%d\n",34) < 0) printf("%m\n"); fclose(arquivo); return 0; }

Sada do cdgo #27.

O erro "bad file descriptor" acontece porque abrimos o arquivo somente para leitura. Se definirmos o modo correto a escrita ocorre normalmente.

Cdigo #27 corrigido.

As funes fputc e putc escrevem apenas um caractere no arquivo, retornando o valor que foi escrito ou EOF em caso de erro, definindo a varivel errno (a essas alturas voc j deve ter reparado que errno.h e printf("%m\n") no so bobagens).

Para escrever uma string no arquivo usamos a funo fputs, que retorna um inteiro no-negativo em caso de sucesso. Caso contrrio, retorna EOF e define errno e o indicador de erro do arquivo (ferror). Outras funes tambm definem esse indicador.

Cdigo #28
#include <stdio.h> #include <errno.h> int main (int argc, char *argv[]) { FILE * arquivo = fopen("novo","a+"); if (!arquivo) { printf("%m\n"); return 1; } if (fputs("asdasd\n",arquivo) == EOF) printf("%m\n"); fclose(arquivo); return 0;

CRIAR ARQUIVO
Alm de podermos criar um arquivo com a chamada a fopen, podemos usar creat, sendo necessrio incluir os headers sys/stat.h] e fcntl.h, embora o modo no seja o mesmo de fopen, pois utilizamos macros (ver funo open). Diferentemente de fopen, creat retorna um descritor de arquivo (inteiro) ao invs de um FILE *.

Cdigo #29
#include <sys/stat.h> #include <fcntl.h> #include <errno.h> int main (int argc, char *argv[]) { creat("novo_arquivo",S_IRUSR| S_IWUSR); return 0; }

Se por acidente uma letra errada for digitada no modo (permisses) utilizada para a criao do arquivo, o erro detectado em tempo de compilao. Mas caso algo diferente d errado, precisamos informar isso ao usurio (e a voc mesmo...). Para saber os valores de retorno da funo creat devemos ler o manual da funo open: QUOTE MAN OPEN
Upon successful completion, the function shall open the file and return a non-negative integer representing the lowest numbered unused file descriptor. Otherwise, -1 shall be returned and errno set to indicate the error. No files shall be created or modified if the function returns -1.

Cdigo #30
#include <sys/stat.h> #include <fcntl.h> #include <errno.h> int main (int argc, char *argv[]) { if (creat("novo_arquivo",S_IRUSR| S_IWUSR) == -1) printf("%m\n"); return 0; }

REMOVER ARQUIVO
A funo remove usada para remover arquivos do disco. Note: ela requer uma string, e no um FILE *. Os valores de retorno so os mesmos de rmdir e unlink: 0 para operao realizada com sucesso e -1 caso tenha ocorrido algum erro,tambm definindo a varivel errno.

Cdigo #31
#include <errno.h> #include <stdio.h> int main (int argc, char *argv[]) { remove("novo_arquivo"); printf("%m\n"); return 0; }

Sada do cdigo #31.

Podemos usar tambm a funo unlink para remover arquivos, devendo incluir unistd.h.

Cdigo #32
#include <errno.h> #include <stdio.h> #include <unistd.h> int main (int argc, char *argv[]) { if (unlink("novo_arquivo") == -1) printf("%m\n"); return 0; }

O comportamento da funo mantido quando o nome indicado como primeiro argumento um link simblico. Links simblicos so "atalhos", referncias para arquivos em outros lugares do sistema. Ao invs de copiar um mesmo arquivo para vrios diretrios e ter que lidar com o problema de atualizar todos eles, cria-se um link simblico. Para localizar todos os links simblicos desde a raiz do sistema execute find / -type l. Quando fazemos referncia a um link simblico a ao "desviada" para onde aponta o link:

possvel que um link simblico esteja quebrado, apontando para um arquivo inexistente no disco:

Cdigo #33
#include <errno.h> #include <stdio.h> #include <unistd.h> int main (int argc, char *argv[]) { if (unlink("/home/isis/LINK_S") == -1) printf("%m\n"); return 0; }

Ao invs de remover o arquivo apontado pelo link (e0xd),a funo remove o link criado. O arquivo original permanece em disco.

Sada do arquivo #33.

RENOMEAR ARQUIVO
A funo rename renomeia um arquivo. Seus dois argumentos so strings e retorna 0 em caso de sucesso e -1 no caso de erro, definindo a varivel errno. Neste caso, os dois arquivos permanecem intactos. A funo se comporta dependendo do tipo de arquivo.

Cdigo #34
#include <errno.h> #include <stdio.h> int main (int argc, char *argv[]) { if (rename("NOVO_LINK","NOVO_ARQUIVO")) printf("%m\n"); return 0; }

Sada do cdigo #34.

Cdigo #35
#include <errno.h> #include <stdio.h> int main (int argc, char *argv[]) { if (rename("xWYT","DIR_EX")) printf("%m\n"); return 0; }

Sada do cdigo #35.

Ou seja, no podemos renomear um arquivo com o nome de um diretrio e nem um diretrio com o nome de um arquivo.

OBTER INFORMAES SOBRE UM ARQUIVO


Suponha que o trabalho pea para exibir informaes sobre um determinado arquivo, tais como o modo, tamanho em bytes, data do ltimo acesso, data da ltima modificao e tipo do arquivo? Abrir com diferentes modos para ver se d erro e abrir o arquivo e contar quantos caracteres existem no so solues muito prticas. Para isso utiliza-se a funo stat. As informaes so guardadas numa struct, mas com tipos diferentes: mode_t, off_t, dev_t, ino_t, nlink_t, uid_t, gid_t, time_t, blksize_t, blkcnt_t. Esses tipos esto definidos em sys/types.h, sendo mode_t, nlink_t, uid_t e gid_t inteiros, blkcnt_t, off_t e blksize_t inteiros com sinal, ino_t inteiro sem sinal e time_t inteiro ou ponto flutuante.

Cdigo #36
#include <errno.h> #include <stdio.h> #include <sys/stat.h> int main (int argc, char *argv[]) { struct stat info; if(stat("xWYT",&info)) printf("%m\n"); else { printf("Modo do arquivo: %d\n", info.st_mode); printf("Tamanho do arquivo em bytes: %d\n",info.st_size); } return 0;

E o que fazemos com st_mode? Existem macros que realizam testes de tipo de arquivo e as permisses (veja o manual de stat.h).

ARQUIVOS TEMPORRIOS
Antes de tudo, um quadro resumo da situao para essas funes: POSIX 2001: tempnam (obsoleto em 2008) tmpfile mkstemp mktemp (removido em 2008) C89: tmpfile tmpnam C99: tmpfile tmpnam Extenso GLIBC: mkostemp No vou falar sobre as duas funes removidas do padro POSIX, ento comeamos com tmpfile. Essa funo no precisa de parmentros, retornando um FILE * vlido ou NULL se ocorrer algum erro (e definindo a varivel errno). O arquivo temporrio criado pela funo criado como "w+" e deletado do disco quando todas as referncias a ele forem fechadas.

Cdigo #37
#include <errno.h> #include <stdio.h> int main (int argc, char *argv[]) { FILE * arquivo = tmpfile(); if(!arquivo) printf("%m\n"); else puts("temporario criado."); fclose(arquivo); return 0; }

A funo mkstemp gera um arquivo temporrio obedecendo a um template para o nome e retorna um descritor de arquivo (inteiro) ao invs de um FILE *. O arquivo criado com as permisses 600 em octal (rw para o dono e nenhuma para o grupo e outros usurios). No caso de erro, retorna -1 e define a varivel errno (entre os erros est a obrigatoriedade dos ltimos 6 caracteres serem X).

Cdigo #38
#include <errno.h> #include <stdio.h> int main (int argc, char *argv[]) { char tmpl[] = "TMP______"; int arquivo = mkstemp(tmpl); if(arquivo == -1) printf("%m\n"); else { puts("temporario criado."); getchar(); } close(arquivo); return 0; }

Cdigo #39
#include <errno.h> #include <stdio.h> int main (int argc, char *argv[]) { char tmpl[] = "TMPXXXXXX"; int arquivo = mkstemp(tmpl); if(arquivo == -1) printf("%m\n"); else { puts("temporario criado."); getchar(); } close(arquivo); return 0; }

Sada do cdigo #39.

A funo tmpnam no gera um arquivo temporrio. Ao invs disso, gera uma string que pode ser usada como nome para um arquivo, sendo que ela nica. O limite de quantidade de strings geradas definido por TMP_MAX, logo, o mximo de vezes que podemos chamar essa funo TMP_MAX, sendo que para mais chamadas o comportamento definido pela implementao. Se a string no puder ser gerada ser retornado NULL e nenhum erro est definido.

Cdigo #40
#include <errno.h> #include <stdio.h> int main (int argc, char *argv[]) { char tmp[50]; char *ptr = tmpnam(tmp); printf("TMP=%s\n", tmp); printf ("ptr=%s\n",ptr); return 0; }

Quando compilamos aparece a mensagem "warning: the use of `tmpnam' is dangerous, better use `mkstemp'", tal como ocorre com gets.

CRIAR DIRETRIOS
Para criar diretrios utilizamos a funo mkdir (sys/stat.h). Seus argumentos so o nome do diretrio e o modo (bits de permisso). O UID (user id) do diretrio o mesmo do UID do processo que cria o diretrio e o GID (group ID) do diretrio recebe o GID do diretrio pai ou do processo que cria o diretrio. O novo diretrio inicialmente est vazio.

Cdigo #41
#include <errno.h> #include <stdio.h> #include <sys/stat.h> int main (int argc, char *argv[]) { if (mkdir("DIR_EX", S_IRWXU)) printf("%m\n"); return 0; }

O valor de retorno da funo em caso de sucesso 0 e caso algo d errado, ela retorna -1 e define a varivel errno. O segundo argumento parece estranho, mas define as permisses do arquivo utilizando o modo Unix. Veja o restante das macros em stat.h. Podemos tambm criar diretrios temporrios utilizando a funo mkdtemp, presente no POSIX-2008, incluindo stdlib.h. Ela semelhante funo mkstemp, ou seja, a string passada como argumento deve ter os 6 ltimos caracteres iguais a 'X'. O diretrio criado com a permisso 700 (acesso total apenas para o dono do diretrio). A funo retorna um ponteiro para o template modificado (que o nome do diretrio - nico) ou NULL em caso de erro, definindo a varivel errno.

LER DIRETRIOS
Para ler sobre a funo scandir veja o tpico Trabalhando com diretrios. Outra maneira de lermos o contedo de um diretrio incluir dirent.h e utilizar a funo readdir, mas devemos abrir o diretrio com opendir primeiro. A funo opendir retorna um ponteiro para um objeto do tipo DIR ou um NULL caso ocorra algum erro, alm de definir a varivel errno.

Cdigo #42
#include <errno.h> #include <stdio.h> #include <dirent.h> int main (int argc, char *argv[]) { DIR * diretorio = opendir("NOVO_DIR"); if (!diretorio) { printf("%m\n"); return 1; } struct dirent * info; while(1) { info = readdir(diretorio); if (!info) { printf("%m\n"); return 3; } printf("ENTRADA: %s\n", info->d_name); }; if (closedir(diretorio) == -1) { printf("%m\n"); return 2; } return 0; }

Nota: A verificao de erros atravs de errno no deve ser feita somente em algumas operaes porque voc acha que algumas tm chances maiores de darem errado.

Sada do cdigo #42.

Detalhe: o final da leitura tambm faz a funo retornar NULL. E caso voc tenha algum cdigo fora do while, ele no ir executar. Para contornar isso podemos utilizar a funo telldir, j que as duas ltimas leituras do diretrio possuem offsets iguais:

Cdigo #43
#include <errno.h> #include <stdio.h> #include <dirent.h> int main (int argc, char *argv[]) { DIR * diretorio = opendir("NOVO_DIR"); if (!diretorio) { printf("%m\n"); return 1; } struct dirent * info; long offset = 0; while(1) { offset = telldir(diretorio); info = readdir(diretorio); if(telldir(diretorio) == offset && !info) break; if (!info) { printf("%m\n"); return 3; } printf("ENTRADA: %s\n", info->d_name); }; if (closedir(diretorio) == -1) { printf("%m\n"); return 2; } return 0;

As duas entradas estranhas, .. e . so, respectivamente, o diretrio pai (~/src/C/Imasters/MEGA-1) e o diretrio atual (~/src/C/Imasters/MEGA-1/NOVO_DIR). A funo rewinddir define a posio do stream de diretrios para o inccio do DIR * passado como argumento, semelhante ao rewind para arquivos. A funo seekdir, assim como seek para arquivos, posiciona o indicador na posio desejada. Deve ser usada em conjunto com telldir. Se esse valor no for obtido via telldir, chamadas a readdir tm o resultado no-especificado.

FILE-TREE WALK
Vamos montar uma lista com o contedo de um diretrio. Por razes bvias usei alocao esttica.

Cdigo #44
#include <errno.h> #include <stdio.h> #include <dirent.h> #include <string.h> #define MAX 20 char lista[20][255]; int elementos = 0; void inclui_diretorio(char * nome) { if (elementos == MAX) return; strcpy(lista[elementos++],nome); } int main (int argc, char *argv[]) { DIR * diretorio = opendir("NOVO_DIR"); if (!diretorio) { printf("%m\n"); return 1; } struct dirent * info; while(1) { info = readdir(diretorio); if (!info) { printf("%m\n"); return 3; } inclui_diretorio(info->d_name); }; if (closedir(diretorio) == -1) { printf("%m\n"); return 2; } puts("Contedo do diretrio:"); for(;elementos > -1;elementos--) printf("%s\n", lista[elementos]); return 0;

Sada do cdigo #44. Entretanto, se tivermos diretrios dentro do diretrio lido, o contedo de cada um deles no ser listado.

Devemos trabalhar com a recurso em diretrios. 1- Entramos em todos os diretrios 2- Samos do diretrio filho ao terminar a leitura, retornando para o diretrio pai 3- Devemos terminar a aplicao quando atingirmos a raiz (o diretrio originalmente aberto), caso contrrio, mudaremos sempre para o diretrio pai at terminarmos ou com erro de permisses ou estourando a memria (caso fosse alocao dinmica) ou na raiz do sistema (/). O primeiro passo verificar se a entrada lida um diretrio. A princpio no precisamos usar stat, porque a struct dirent possui um campo d_type, que visa justamente nos poupar o chamado de lstat. Por enquanto temos o seguinte pedao de cdigo:

Cdigo #45
while(1) { offset = telldir(diretorio); info = readdir(diretorio); if (info->d_type == DT_DIR && strcmp(info->d_name,"..") && strcmp(info->d_name,".")) { if (chdir(info->d_name) == -1) printf("%m\n"); else continue; } if (telldir(diretorio) == offset && !info) break; if (!info) { printf("%m\n"); return 3; } inclui_diretorio(info->d_name); };

Execute o cdigo com essas alteraes acima. Chdir resulta em erro; diretrio no encontrado. O problema que estamos no diretrio ~/ src/C/Imasters/MEGA-1 e no em ~/src/C/Imasters/MEGA-1/NODO_DIR, onde se encontra o diretrio EX. Precisamos mudar o diretrio atual, com chdir.

Cdigo #46
DIR * diretorio = opendir("NOVO_DIR"); if (!diretorio) { printf("%m\n"); return 1; } struct dirent * info; long offset = 0; if (chdir("NOVO_DIR") == -1) { printf("%m\n"); return 4; }

Executando novamente ainda vemos a falha de segmentao. Isso acontece porque estamos no diretrio EX, mas a varivel diretrio faz referncia ao diretrio NOVO_DIR. Ou seja, temos que mudar totalmente o modo como o programa escrito, utilizando alocao dinmica (pilha), pois no sabemos quantos diretrios existem nessa rvore. Teramos algo parecido com isto:

Cdigo #47
#include <errno.h> #include <stdio.h> #include <dirent.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #define MAX 255 char **lista_arquivos; char **lista_diretorios; int arquivos = 0; int diretorios = 0; int main (int argc, char *argv[]) { DIR * diretorio = opendir("NOVO_DIR"); if (!diretorio) { printf("%m\n"); return 1; } struct dirent * info; long offset = 0; if (chdir("NOVO_DIR") == -1) { printf("%m\n"); return 4; } char T[MAX]; while(1) { getcwd(T,MAX); printf("==>%s\n",T); offset = telldir(diretorio); info = readdir(diretorio); if (info->d_type == DT_DIR && strcmp(info->d_name,"..") && strcmp(info->d_name,".")) { printf("Encontrei um diretrio. %s\n",info->d_name); if(!diretorios) { lista_diretorios = (char**) malloc(sizeof(char*)); if (!lista_diretorios) { printf("%m\n"); exit(1); } } else { lista_diretorios = (char**) realloc(lista_diretorios,(diretorios+1)*sizeof(char*)); if (!lista_diretorios) { printf("%m\n"); exit(1); } } lista_diretorios[diretorios] = (char*)malloc(MAX);

diretorios++; strcpy(lista_diretorios[diretorios-1],info->d_name); diretorio = opendir(info->d_name); if (!diretorio) { printf("%m\n"); return 1; } if (chdir(info->d_name) == -1) { printf("%m\n"); return 1; } continue; } // fim do if para comparao de diretrio. if (telldir(diretorio) == offset && !info){ if (!diretorios) break; else { closedir(diretorio); free(lista_diretorios[diretorios-1]); lista_diretorios[diretorios-1] = NULL; diretorios--; continue; } } if (!info) { printf("%m\n"); return 3; } if(!arquivos) { lista_arquivos = (char**) malloc(sizeof(char*)); if (!lista_arquivos) { printf("%m\n"); exit(1); } } else { lista_arquivos = (char**) realloc(lista_arquivos,(arquivos+1)*sizeof(char*)); if (!lista_arquivos) { printf("%m\n"); exit(1); } } lista_arquivos[arquivos] = (char*)malloc(MAX); strcpy(lista_arquivos[arquivos++],info->d_name); }; if (closedir(diretorio) == -1) { printf("%m\n"); return 2; } puts("Contedo do diretrio:"); for(;arquivos > -1;arquivos--) printf("%s\n", lista_arquivos[arquivos]); return 0;

E provavelmente ainda faltam coisas, porque continua dando falha de segmentao. Por exemplo: quando chegamos ao final de um diretrio filho, devemos, alm de retir-lo da lista, retornar ao diretrio pai, mas no podemos usar opendir, caso contrrio, retornamos ao incio do diretrio. Ento devemos ter uma struct com a posio da ltima leitura no diretrio para utilizar com seekdir.

Cdigo #48
#include <errno.h> #include <stdio.h> #include <dirent.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #define MAX 255 typedef struct { int contagem; char **lista_arquivos; } ARQUIVOS; typedef struct{ int contagem; char ** lista_diretorios; long ** offset; } DIRETORIOS; int main (int argc, char *argv[]) { DIR * diretorio = opendir("NOVO_DIR"); if (!diretorio) { printf("%m\n"); return 1; } struct dirent * info; if (chdir("NOVO_DIR") == -1) { printf("%m\n"); return 4; } char T[MAX]; long offset = 0; ARQUIVOS Farq; Farq.contagem = 0; DIRETORIOS Fdir; Fdir.contagem = 0; while(1) { getcwd(T,MAX); printf("==>%s\n",T); offset = telldir(diretorio); info = readdir(diretorio); if (info->d_type == DT_DIR && strcmp(info->d_name,"..") && strcmp(info->d_name,".")) { printf("Encontrei um diretrio. %s\n",info->d_name); if(!Fdir.contagem) { Fdir.lista_diretorios = (char**) malloc(sizeof(char*)); if (!Fdir.lista_diretorios) { printf("%m\n"); exit(1); }

Fdir.offset = (long **)malloc(sizeof(long*)); if (!Fdir.offset) { printf("%m\n"); exit(1); } } else { Fdir.lista_diretorios = (char**) realloc(Fdir.lista_diretorios,(Fdir.contagem+1)*sizeof(char*)); if (!Fdir.lista_diretorios) { printf("%m\n"); exit(1); } Fdir.offset = (long **)realloc(Fdir.offset,(Fdir.contagem+1) *sizeof(long*)); if (!Fdir.offset) { printf("%m\n"); exit(1); }

Fdir.lista_diretorios[Fdir.contagem] = (char*)malloc(MAX); Fdir.offset[Fdir.contagem] = (long*)malloc(sizeof(long)); Fdir.contagem++; strcpy(Fdir.lista_diretorios[Fdir.contagem-1],info->d_name); (*Fdir.offset[Fdir.contagem-1]) = telldir(diretorio); diretorio = opendir(info->d_name); if (!diretorio) { printf("%m\n"); return 1; } if (chdir(info->d_name) == -1) { printf("%m\n"); return 1; } continue; } // fim do if para comparao de diretrio. if (telldir(diretorio) == offset && !info){ if (!Fdir.contagem) break; else { closedir(diretorio); free(Fdir.lista_diretorios[Fdir.contagem-1]); Fdir.lista_diretorios[Fdir.contagem-1] = NULL; Fdir.contagem--; chdir(".."); diretorio = opendir(Fdir.lista_diretorios[Fdir.contagem-1]); seekdir(diretorio,(*Fdir.offset[Fdir.contagem-1])); continue; } } if (!info) { printf("%m\n"); return 3; } if(!Farq.contagem) {

Farq.lista_arquivos = (char**) malloc(sizeof(char*)); if (!Farq.lista_arquivos) { printf("%m\n"); exit(1); } } else { Farq.lista_arquivos = (char**) realloc(Farq.lista_arquivos,(Farq.contagem+1)*sizeof(char*)); if (!Farq.lista_arquivos) { printf("%m\n"); exit(1); } } Farq.lista_arquivos[Farq.contagem] = (char*)malloc(MAX); strcpy(Farq.lista_arquivos[Farq.contagem++],info->d_name);

};

if (closedir(diretorio) == -1) { printf("%m\n"); return 2; } puts("Contedo do diretrio:"); for(;Farq.contagem > -1;Farq.contagem--) printf("%s\n", Farq.lista_arquivos[Farq.contagem]); return 0; }

E ainda temos falha de segmentao. Nesse ponto quem tem o header ftw.h est melhor arranjado, j que pode substituir toda aquela confuso acima por 2 chamadas de funo. Esse header define duas funes: ftw e nftw. Comecemos com ftw. O que ftw faz percorrer o diretrio raiz especificado no primeiro argumento (const char *) recursivamente, chamando uma funo especificada no segundo argumento (emprega o conceito de ponteiro para funo) com os seguintes argumentos: o nome do objeto, um ponteiro para uma struct stat com informaes sobre o objeto e um inteiro. O conceito de ponteiro para funo simples, mas a notao diferente da notao de ponteiro para uma estrutura ou tipo de dado:

Conceito de ponteiro para funo ilustrado. O inteiro (3 argumento da funo chamada por ftw) pode ser: FTW_D (diretrio), FTW_DNR (diretrio que no se pode ler), FTW_F (arquivo), FTW_SL (link simblico) e FTW_NS (para outro objeto se stat no pde ser executado com sucesso. Se o objeto for um link simblico e o stat falhou, no est especificado se ftw passa FTW_SL ou FTW_NS). O terceiro argumento da funo ftw um inteiro que especifica o nmero mximo de descritores de arquivo utilizados para o diretrio, devendo ser menor do que OPEN_MAX (consulte os manuais). Ento, para criar uma lista de arquivos temos:

Cdigo #49
#include #include #include #include #include <stdio.h> <errno.h> <ftw.h> <stdlib.h> <string.h>

char **lista_arquivos; int arquivos = 0; int check_mem(void * PTR) { if (!PTR) { printf("%m\n"); return(1); } } int insere_arquivos(const char * S, const struct stat *P, int F) { if (F == FTW_F) { if (!arquivos) lista_arquivos = (char **)malloc(sizeof(char*)); else lista_arquivos = (char **)realloc(lista_arquivos,(arquivos+1)*sizeof(char*)); check_mem(lista_arquivos); lista_arquivos[arquivos] = (char*) malloc(strlen(S)); check_mem(lista_arquivos[arquivos]); strcpy(lista_arquivos[arquivos],S); arquivos++; } else if (F == FTW_D) printf("Diretrio encontrado: %s\n",S); return 0; } int main (int argc, char *argv[]) { if (ftw("NOVO_DIR",insere_arquivos,10)) { printf("%m\n"); return 1; } for(arquivos-=1;arquivos > -1;arquivos--) printf("%s\n",lista_arquivos[arquivos]); return 0;

Sada do cdigo #49.

BEM mais enxuto do que os cdigos anteriores. J a funo nftw possui um argumento a mais na funo chamada: um ponteiro para struct. Alm disso, existe ainda um quarto argumento na funo, um inteiro que especifica o comportamento da funo: FTW_CHDIR : a cada diretrio encontrado, a funo realiza um chdir para o diretrio. FTW_DEPTH : retorna todos os arquivos de um diretrio antes de retornar o prprio diretrio. FTW_MOUNT: nftw retorna arquivos somente no mesmo sistema de arquivo que o diretrio raiz. FTW_PHYS: no segue links simblicos. A cada entrada do diretrio a funo nftw chama a funo especificada no segundo argumento, com um parmetro extra: uma struct com os membros base (offset do objeto no caminho passado como primeiro argumento da funo chamada) e level (nvel do arquivo, sendo 0 o diretrio raiz).

Cdigo #50
#include #include #include #include #include <stdio.h> <errno.h> <ftw.h> <stdlib.h> <string.h>

char **lista_arquivos; int arquivos = 0; int check_mem(void * PTR) { if (!PTR) { printf("%m\n"); return(1); } } int insere_arquivos(const char * S, const struct stat *P, int F, struct FTW *ftwbuf) { if (F == FTW_F) { if (!arquivos) lista_arquivos = (char **)malloc(sizeof(char*)); else lista_arquivos = (char **)realloc(lista_arquivos,(arquivos+1)*sizeof(char*)); check_mem(lista_arquivos); lista_arquivos[arquivos] = (char*) malloc(strlen(S)); check_mem(lista_arquivos[arquivos]); strcpy(lista_arquivos[arquivos],S); arquivos++; } else if (F == FTW_D) printf("Diretrio encontrado: %s\n",S); printf("Nvel: %d\n", ftwbuf->level); return 0; } int main (int argc, char *argv[]) { if (nftw("NOVO_DIR",insere_arquivos,5,FTW_CHDIR)) { printf("%m\n"); return 1; } for(arquivos-=1;arquivos > -1;arquivos--) printf("%s\n",lista_arquivos[arquivos]); return 0;

Sada do cdigo #50.

Erros de compilao. Para usar nftw precisamos definir a macro _XOPEN_SOURCE 500. Mas mesmo fazendo isso no fonte, continuamos com erro de compilao. Devemos defini-la na linha do compilador:

Sada do cdigo #50 com a macro _XOPEN_SOURCE definida.

Sada do cdigo #50 com flag FTW_DEPTH.

Sada do cdigo #50 com flag FTW_MOUNT.

Sada do cdigo #50 com flag FTW_PHYS. No existe outro filesystem sendo usado. Um detalhe do manual da funo: os resultados no so especificados se a funo chamada por nftw no preservar o diretrio de trabalho atual. Ou seja, se voc utilizar chdir na funo passada como argumento para nftw pode ser que nada funcione.

REMOVER DIRETRIOS
Para remover diretrios podemos utilizar a funo rmdir, definida em unistd.h, que aceita uma string correspondente ao nome do diretrio a ser removido. O valor de retorno 0 em caso de sucesso e -1 caso contrrio, definindo a varivel errno.

Cdigo #51
#include <stdio.h> #include <errno.h> #include <unistd.h> int main(int argc, char *argv[]) { if(rmdir(NOVO_DIR)) printf(%m\n); return 0; }

Sada do cdigo #51.

Cdigo #52
#include <stdio.h> #include <errno.h> #include <unistd.h> int main(int argc, char *argv[]) { if(rmdir(NOVO_DIR/DIR_EX)) printf(%m\n); return 0; }

Sada do cdigo #52. Detalhe: ao contrrio de arquivos, no podemos utilizar a funo unlink para remover diretrios.

Cdigo #53
#include <stdio.h> #include <errno.h> #include <unistd.h> int main(int argc, char *argv[]) { if(rmdir(novo_arquivo)) printf(%m\n); return 0; }

Sada do cdigo #53.

OUTRAS OPERAES COM DIRETRIOS


A funo dirname (POSIX 2001), em libgen.h, retorna um ponteiro para um array de caracteres que contm o caminho do diretrio pai do arquivo especificado.

Cdigo #54
#include <stdio.h> #include <errno.h> #include <libgen.h> int main(int argc, char *argv[]) { char *S; S = dirname(TESTE_DIR); if(S) printf(%s\n,S); return 0; }

Sada do cdigo #54.

Note que ao especificar um diretrio que no existe o retorno '.' (diretrio atual).

Cdigo #55
#include <stdio.h> #include <errno.h> #include <libgen.h> int main(int argc, char *argv[]) { char *S; S = dirname(/home/isis); if(S) printf(%s\n,S); return 0; }

Sada do cdigo #55.

Cdigo #56
#include <stdio.h> #include <errno.h> #include <libgen.h> int main(int argc, char *argv[]) { char *s = ~/xWYT; char *t = dirname(s); if(t) printf(%s\n,t); return 0; }

Sada do cdigo #56.

Cdigo #57
#include <stdio.h> #include <errno.h> #include <libgen.h> int main(int argc, char *argv[]) { char s[] = ~/xWYT; char *t = dirname(s); if(t) printf(%s\n,t); return 0; }

Sada do cdigo #57.

A funo basename (POSIX) retorna o ltimo componente no caminho at um arquivo.

Cdigo #58
#include <stdio.h> #include <errno.h> #include <libgen.h> int main(int argc, char *argv[]) { char s[] = ~/xWYT; char *t = basename(s); if(t) printf(%s\n,t); return 0; }

Sada do cdigo #58.

A funo chdir (unistd.h) modifica o diretrio de trabalho. Em caso de sucesso retorna 0, caso contrrio retorna -1 e define a varivel errno. Utilizando getcwd (unistd.h)podemos saber qual o diretrio atual.

Cdigo #59
#include <stdio.h> #include <errno.h> #include <unistd.h> int main(int argc, char *argv[]) { char s[256]; char *t = getcwd(s,256); if(t) printf(%s\n,t); return 0; }

Sada do cdigo #59.