Menu

PHP fopen(): abrir, ler e escrever arquivos (modos)

fopen('data.txt', 'r') abre um arquivo e retorna um handle, ou false em caso de falha. Leia do handle com fgets() ou fread(), escreva com fwrite() e feche com fclose(). O modo ('r', 'w', 'a', 'x', 'c' e as formas com +) decide o que você pode fazer.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

fopen('data.txt', 'r') abre um arquivo e retorna um handle, um recurso de stream que as outras funções de arquivo recebem como primeiro argumento. Leia com fgets() (uma linha) ou fread() (uma quantidade de bytes), escreva com fwrite() e feche com fclose(). O segundo argumento é o modo: 'r' para ler, 'w' para escrever, 'a' para acrescentar.

Saída:

Got: apple
Got: banana
Got: cherry

O fopen() retorna false quando não consegue abrir o arquivo (ele não existe no modo r, falta uma pasta, não há permissão), e o PHP imprime um aviso como:

Warning: fopen(missing.txt): Failed to open stream: No such file or directory in /home/index.php on line 2

Então verifique o false antes de usar o handle. Para ler ou escrever um arquivo pequeno inteiro numa chamada, file_get_contents() e file_put_contents() são mais curtos; o fopen() é para arquivos que você lê aos poucos ou mantém abertos.

Modos do fopen

ModoLêEscreveSe o arquivo existeSe não existeComeça em
rsimnãoabrefalhainício
r+simsimabre, mantém o conteúdofalhainício
wnãosimesvaziacriainício
w+simsimesvaziacriainício
anãosimmantém o conteúdocriafim, toda escrita acrescenta
a+simsimmantém o conteúdocriafim, toda escrita acrescenta
xnãosimfalhacriainício
x+simsimfalhacriainício
cnãosimmantém o conteúdocriainício
c+simsimmantém o conteúdocriainício

Duas linhas surpreendem. r+ escreve por cima dos bytes existentes no lugar, sem inserir, e a+ sempre escreve no fim, mesmo depois de você mover o ponteiro com fseek() (movê-lo só afeta as leituras):

Saída:

Xbc
Xbc
Xbc
end

No Windows você pode ver 'rb' ou 'wb': a flag b significa binário e impede o Windows de traduzir os fins de linha. Ela não faz nada no Linux e no macOS, então adicioná-la é inofensivo e portável.

Ler um arquivo linha por linha com fgets()

O fgets() retorna a próxima linha incluindo o \n, e false no fim do arquivo. Como só uma linha fica na memória por vez, este loop lida com um arquivo de log de qualquer tamanho, e você pode parar cedo com break:

Saída:

2 errors in 5 lines
line 2: database timeout
line 4: disk full

Compare com false usando !==, não com um simples while ($line = fgets($fh)): uma linha contendo só "0" sem quebra de linha (a última linha de um arquivo pode ser assim) é falsa e encerraria o loop antes da hora.

Escrever e acrescentar com fwrite()

O fwrite() escreve uma string na posição atual e retorna o número de bytes escritos, ou false em caso de falha. O fputs() é a mesma função com outro nome. Abra com 'a' para acrescentar ao fim de um arquivo sem mexer no que está lá:

Saída:

wrote 12 bytes
wrote 13 bytes
wrote 15 bytes
visit /home
visit /about
visit /contact
visit /home

PHP_EOL é o fim de linha do sistema em que o PHP roda (\n no Linux e no macOS, \r\n no Windows). Para arquivos que outros programas leem, escolha um explicitamente, normalmente "\n".

Ler e escrever arquivos CSV com fgetcsv() e fputcsv()

O fputcsv() escreve um array como uma linha CSV e coloca entre aspas os campos que contêm vírgulas, aspas ou quebras de linha. O fgetcsv() lê uma linha de volta como array. Passe explicitamente o separador, o delimitador de texto e um caractere de escape vazio: isso dá CSV padrão, e o PHP 8.4 imprime um aviso de depreciação quando o argumento de escape é omitido.

Saída:

name,city,note
Ada,London,"likes ""math"", a lot"
Linus,Helsinki,kernel

Ada lives in London: likes "math", a lot
Linus lives in Helsinki: kernel

Dividir linhas com explode(',', $line) quebra assim que um campo contém uma vírgula; o fgetcsv() trata as aspas para você. Para um arquivo separado por ponto e vírgula (comum em exportações do Excel na Europa), passe ';' como separador.

Mover-se num arquivo com fseek(), ftell() e rewind()

Um arquivo aberto tem uma posição. Leituras e escritas começam ali e a movem para a frente. O ftell() diz onde ela está, o fseek() a move para um offset em bytes, e o rewind() volta ao início. Com w+ você pode escrever um arquivo e lê-lo de volta pelo mesmo handle:

Saída:

11
world
hello world

Travar um arquivo com flock()

Duas requisições que leem um contador, somam um e o escrevem de volta ao mesmo tempo podem as duas ler 41 e as duas escrever 42. O flock() com LOCK_EX faz a segunda esperar até a primeira liberar o lock. O modo c+ é o certo aqui: ele cria o arquivo se necessário e, ao contrário do w+, não o esvazia antes de você ter o lock.

Saída:

Visitor number 1
Visitor number 2
Visitor number 3

Os locks são consultivos: só impedem outro código que também chama flock(). Para acrescentar uma linha, file_put_contents($path, $line, FILE_APPEND | LOCK_EX) faz o mesmo numa chamada.

Erro comum: while (!feof($fh))

Muitos tutoriais antigos fazem o loop com feof(). Ele só retorna true depois que uma leitura já chegou ao fim, então o loop roda uma vez a mais do que há linhas e o último fgets() retorna false:

Saída:

string(2) "a
"
string(2) "b
"
string(2) "c
"
bool(false)
4 rounds for 3 lines

Esse false extra vira uma linha vazia num relatório ou um elemento vazio num array. Faça o loop na própria leitura, while (($line = fgets($fh)) !== false), como todos os outros exemplos desta página.

Perguntas frequentes

Quais são os modos do fopen no PHP?

r lê, w escreve depois de esvaziar o arquivo, a escreve no fim, x cria um arquivo novo e falha se ele existir, e c escreve sem esvaziá-lo. Adicionar + (r+, w+, a+, x+, c+) permite ler e escrever. Todos os modos exceto r e r+ criam o arquivo quando ele não existe.

Qual a diferença entre w e a no fopen?

w esvazia o arquivo assim que ele é aberto e escreve a partir do início. a mantém o conteúdo e todo fwrite() vai para o fim do arquivo, mesmo depois de um fseek(), o que o torna o modo para arquivos de log.

Como leio um arquivo CSV no PHP?

Abra-o com fopen($path, 'r') e chame fgetcsv() num loop: while (($row = fgetcsv($fh, null, ',', '"', '')) !== false) { ... }. Cada chamada retorna uma linha como array de campos, com aspas e vírgulas internas tratadas para você.

Preciso chamar fclose no PHP?

O PHP fecha todos os arquivos abertos quando o script termina, então um script curto funciona sem ele. Chame fclose() mesmo assim assim que terminar: ele descarrega escritas em buffer, libera locks obtidos com flock() e impede que um script de longa duração fique sem handles de arquivo.

Ilustração das linguagens de programação do Coddy

Aprenda a programar com o Coddy

COMEÇAR