¿Desea marcar como respuesta en cualquiera de los siguientes?
Kim Stacks
Respuestas:
685
Puede usar la fgets()función para leer el archivo línea por línea:
$handle = fopen("inputfile.txt","r");if($handle){while(($line = fgets($handle))!==false){// process the line read.}
fclose($handle);}else{// error opening the file.}
¿Cómo explica esto la too large to open in memoryparte?
Starx
64
No está leyendo todo el archivo en la memoria. La memoria máxima necesaria para ejecutar esto depende de la línea más larga en la entrada.
codaddict
13
@Brandin - Moot - En esas situaciones, la pregunta formulada, que es leer un archivo LÍNEA A LÍNEA, no tiene un resultado bien definido.
ToolmakerSteve
3
@ToolmakerSteve Luego defina lo que debe suceder. Si lo desea, puede imprimir el mensaje "Línea demasiado larga; darse por vencido". y ese es un resultado bien definido también.
Brandin
2
¿Puede una línea contener un booleano falso? Si es así, este método se detendría sin llegar al final del archivo. El Ejemplo # 1 en esta URL php.net/manual/en/function.fgets.php sugiere que los fgets a veces pueden devolver boolean false aunque aún no se haya alcanzado el final del archivo. En la sección de comentarios de esa página, las personas informan que fgets () no siempre devuelve los valores correctos, por lo que es más seguro usar feof como condicional de bucle.
cjohansson
131
if($file = fopen("file.txt","r")){while(!feof($file)){
$line = fgets($file);# do same stuff with the $line}
fclose($file);}
Como dijo @ Cuse70 en su respuesta, esto conducirá a un bucle infinito si el archivo no existe o no se puede abrir. Prueba if($file)antes del ciclo while
FrancescoMM
10
Sé que esto es viejo, pero: no se recomienda usar while (! Feof ($ file)). Echa un vistazo aquí.
<?php
$file =newSplFileObject("file.txt");// Loop until we reach the end of the file.while(!$file->eof()){// Echo one line from the file.
echo $file->fgets();}// Unset the file to call __destruct(), closing the file handle.
$file =null;
Gracias. Sí, por ejemplo, puede agregar esta línea antes mientras $ file-> setFlags (SplFileObject :: DROP_NEW_LINE); para soltar nuevas líneas al final de una línea.
elshnkhll
Por lo que puedo ver, ¿no hay ninguna eof()función en SplFileObject?
Chud37
3
¡Gracias! Además, use rtrim($file->fgets())para quitar las nuevas líneas finales para cada cadena de línea que se lee si no las desea.
Esta debería ser una respuesta aceptada en su lugar. Es cien veces más rápido con generadores.
Tachi
1
Y mucho más eficiente en memoria.
Nino Škopac
2
@ NinoŠkopac: ¿Puede explicar por qué esta solución es más eficiente en memoria? Por ejemplo, en comparación con el SplFileObjectenfoque.
k00ni
30
Use técnicas de almacenamiento en búfer para leer el archivo.
$filename ="test.txt";
$source_file = fopen( $filename,"r")ordie("Couldn't open $filename");while(!feof($source_file)){
$buffer = fread($source_file,4096);// use a buffer of 4KB
$buffer = str_replace($old,$new,$buffer);///}
esto merece más amor, ya que funcionará con archivos enormes, incluso archivos que no tienen retornos de carro o líneas extremadamente largas ...
Jimmery
No me sorprendería si el OP realmente no se preocupara por las líneas reales y solo quisiera, por ejemplo, publicar una descarga. En ese caso, esta respuesta está bien (y lo que la mayoría de los codificadores de PHP harían de todos modos).
Álvaro González el
30
Hay una file()función que devuelve una matriz de líneas contenidas en el archivo.
El archivo de un GB se leería todo en la memoria y se convertiría en una matriz de más de un GB ... buena suerte.
FrancescoMM
44
Esta no fue la respuesta a la pregunta formulada, pero sí responde a la pregunta más común que muchas personas tienen al mirar aquí, por lo que fue útil, gracias.
pilavdzice
2
file () es muy conveniente para trabajar con archivos pequeños. Especialmente cuando quieres una matriz () como resultado final.
functionvoid
esta es una mala idea con archivos más grandes ya que todo el archivo se está leyendo en una matriz a la vez
Flash Thunder
Esto se rompe mal en archivos grandes, por lo que es exactamente el método que no funciona.
La respuesta obvia no estaba allí en todas las respuestas.
PHP tiene un analizador delimitador de transmisión ordenado disponible hecho exactamente para ese propósito.
Cabe señalar que este código devolverá solo líneas hasta que ocurra la primera línea vacía. Necesita probar $ line! == false en la condición while (($line = stream_get_line($fp, 1024 * 1024, "\n")) !== false)
while
8
Tenga cuidado con las cosas 'while (! Feof ... fgets ()', los fgets pueden obtener un error (returnfing false) y repetirse para siempre sin llegar al final del archivo. Codaddict estuvo más cerca de ser correcto pero cuando su 'while fgets' el ciclo termina, verifique feof; si no es cierto, entonces tuvo un error.
Así es como lo manejo con un archivo muy grande (probado con hasta 100G). Y es más rápido que fgets ()
$block =1024*1024;//1MB or counld be any higher than HDD block_size*2if($fh = fopen("file.txt","r")){
$left='';while(!feof($fh)){// read the file
$temp = fread($fh, $block);
$fgetslines = explode("\n",$temp);
$fgetslines[0]=$left.$fgetslines[0];if(!feof($fh))$left = array_pop($lines);foreach($fgetslines as $k => $line){//do smth with $line}}}
fclose($fh);
¿Cómo se asegura de que el bloque 1024 * 1024 no se rompa en el medio de la línea?
user151496
1
@ user151496 fácil !! contar ... 1.2.3.4
Omar El Don
@OmarElDon, ¿qué quieres decir?
Codex73
7
Una de las soluciones populares a esta pregunta tendrá problemas con el nuevo carácter de línea. Se puede arreglar bastante fácil con un simple str_replace.
function read_file($filename =''){
$buffer = array();
$source_file = fopen( $filename,"r")ordie("Couldn't open $filename");while(!feof($source_file)){
$buffer[]= fread($source_file,4096);// use a buffer of 4KB}return $buffer;}
Esto crearía una única matriz de más de un GB en memoria (buena suerte con ella) dividida ni siquiera en líneas sino en fragmentos arbitrarios de 4096 caracteres. ¿Por qué demonios querrías hacer eso?
fgets()
sin$length
parámetro.Respuestas:
Puede usar la
fgets()
función para leer el archivo línea por línea:fuente
too large to open in memory
parte?fuente
if($file)
antes del ciclo whilefeof()
ya no existe?Puede usar una clase de interfaz orientada a objetos para un archivo: SplFileObject http://php.net/manual/en/splfileobject.fgets.php (PHP 5> = 5.1.0)
fuente
eof()
función en SplFileObject?rtrim($file->fgets())
para quitar las nuevas líneas finales para cada cadena de línea que se lee si no las desea.Si está abriendo un archivo grande, probablemente quiera usar Generadores junto con fgets () para evitar cargar todo el archivo en la memoria:
Úselo así:
De esta forma, puede procesar líneas de archivo individuales dentro de foreach ().
Nota: los generadores requieren> = PHP 5.5
fuente
SplFileObject
enfoque.Use técnicas de almacenamiento en búfer para leer el archivo.
fuente
Hay una
file()
función que devuelve una matriz de líneas contenidas en el archivo.fuente
fuente
file()
.La respuesta obvia no estaba allí en todas las respuestas.
PHP tiene un analizador delimitador de transmisión ordenado disponible hecho exactamente para ese propósito.
fuente
while (($line = stream_get_line($fp, 1024 * 1024, "\n")) !== false)
Tenga cuidado con las cosas 'while (! Feof ... fgets ()', los fgets pueden obtener un error (returnfing false) y repetirse para siempre sin llegar al final del archivo. Codaddict estuvo más cerca de ser correcto pero cuando su 'while fgets' el ciclo termina, verifique feof; si no es cierto, entonces tuvo un error.
fuente
Así es como lo manejo con un archivo muy grande (probado con hasta 100G). Y es más rápido que fgets ()
fuente
Una de las soluciones populares a esta pregunta tendrá problemas con el nuevo carácter de línea. Se puede arreglar bastante fácil con un simple
str_replace
.fuente
SplFileObject es útil cuando se trata de manejar archivos grandes.
fuente
fuente
Función para leer con retorno de matriz
fuente