PHP
Filhantering
Sök…
Syntax
- int readfile (string $ filnamn [, bool $ use_include_path = false [, resource $ context]])
parametrar
Parameter | Beskrivning |
---|---|
filnamn | Filnamnet som läses. |
use_include_path | Du kan använda den andra tillvalsparametern och ställa in den till SANT om du också vill söka efter filen i inkludera sökvägen. |
sammanhang | En resurs för kontextström. |
Anmärkningar
Filnamnssyntax
De flesta filnamn som skickas till funktioner i detta ämne är:
- Strängar i naturen.
- Filnamn kan skickas direkt. Om värden av andra typer skickas, kastas de till sträng. Detta är särskilt användbart med
SplFileInfo
, som är värdet i iterationen avDirectoryIterator
.
- Filnamn kan skickas direkt. Om värden av andra typer skickas, kastas de till sträng. Detta är särskilt användbart med
- Relativ eller absolut.
- Acceptera protokoll.
- De kan börja med
scheme://
att ange protokollomslaget att hantera med. Till exempelfile_get_contents("http://example.com")
innehåll från http://example.com .
- De kan börja med
- Slash-kompatibla.
- Medan
DIRECTORY_SEPARATOR
Windows är ett backslash, och systemet returnerar backslags för sökvägar som standard, kan utvecklaren fortfarande använda/
som katalogseparator. Därför, för kompatibilitet, kan utvecklare använda/
som katalogseparatorer på alla system, men vara medvetna om att de värden som returneras av funktionerna (t.ex.realpath
) kan innehålla backstänger.
- Medan
Radera filer och kataloger
Radera filer
unlink
funktionen raderar en enda fil och returnerar om operationen var framgångsrik.
$filename = '/path/to/file.txt';
if (file_exists($filename)) {
$success = unlink($filename);
if (!$success) {
throw new Exception("Cannot delete $filename");
}
}
Radera kataloger, med rekursiv radering
Å andra sidan bör kataloger tas bort med rmdir
. Men den här funktionen raderar bara tomma kataloger. Om du vill ta bort en katalog med filer tar du först bort filerna i katalogerna. Om katalogen innehåller underkataloger kan rekursion behövas.
Följande exempel skannar filer i en katalog, raderar medlemsfiler / kataloger rekursivt och returnerar antalet filer (inte kataloger) som har raderats.
function recurse_delete_dir(string $dir) : int {
$count = 0;
// ensure that $dir ends with a slash so that we can concatenate it with the filenames directly
$dir = rtrim($dir, "/\\") . "/";
// use dir() to list files
$list = dir($dir);
// store the next file name to $file. if $file is false, that's all -- end the loop.
while(($file = $list->read()) !== false) {
if($file === "." || $file === "..") continue;
if(is_file($dir . $file)) {
unlink($dir . $file);
$count++;
} elseif(is_dir($dir . $file)) {
$count += recurse_delete_dir($dir . $file);
}
}
// finally, safe to delete directory!
rmdir($dir);
return $count;
}
Bekvämlighetsfunktioner
Rå direkt IO
file_get_contents
och file_put_contents
ger möjlighet att läsa / skriva från / till en fil till / från en PHP-sträng i ett enda samtal.
file_put_contents
kan också användas med FILE_APPEND
bitmaskflaggan för att lägga till, istället för att trunkera och skriva över, filen. Det kan användas tillsammans med LOCK_EX
bitmask för att skaffa ett exklusivt lås för filen medan du fortsätter att skriva. Bitmaskerflaggor kan förenas med |
bitvis-ELLER operatör.
$path = "file.txt";
// reads contents in file.txt to $contents
$contents = file_get_contents($path);
// let's change something... for example, convert the CRLF to LF!
$contents = str_replace("\r\n", "\n", $contents);
// now write it back to file.txt, replacing the original contents
file_put_contents($path, $contents);
FILE_APPEND
är praktiskt för att lägga till loggfiler medan LOCK_EX
hjälper till att förhindra LOCK_EX
från flera processer. För att till exempel skriva till en loggfil om den aktuella sessionen:
file_put_contents("logins.log", "{$_SESSION["username"]} logged in", FILE_APPEND | LOCK_EX);
CSV IO
fgetcsv($file, $length, $separator)
fgetcsv
från öppen fil som kontrollerar efter csv-fält. Det returnerar CSV-fält i en matris om framgång eller FALSE
on fail.
Som standard läser den bara en rad i CSV-filen.
$file = fopen("contacts.csv","r");
print_r(fgetcsv($file));
print_r(fgetcsv($file,5," "));
fclose($file);
contacts.csv
Kai Jim, Refsnes, Stavanger, Norway
Hege, Refsnes, Stavanger, Norway
Produktion:
Array
(
[0] => Kai Jim
[1] => Refsnes
[2] => Stavanger
[3] => Norway
)
Array
(
[0] => Hege,
)
Läser en fil till stdout direkt
readfile
kopierar en fil till utgångsbufferten. readfile () kommer inte att presentera några minnesproblem, ens när du skickar stora filer, på egen hand.
$file = 'monkey.gif';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
Eller från en filpekare
Alternativt, för att söka efter en punkt i filen för att börja kopiera till stdout, använd istället fpassthru
. I följande exempel kopieras de sista 1024 byte till stdout:
$fh = fopen("file.txt", "rb");
fseek($fh, -1024, SEEK_END);
fpassthru($fh);
Läser en fil i en matris
file
returnerar raderna i den skickade filen i en matris. Varje element i matrisen motsvarar en rad i filen, med den nya linjen fortfarande bifogad.
print_r(file("test.txt"));
test.txt
Welcome to File handling
This is to test file handling
Produktion:
Array
(
[0] => Welcome to File handling
[1] => This is to test file handling
)
Få filinformation
Kontrollera om en sökväg är en katalog eller en fil
Funktionen is_dir
returnerar om argumentet är en katalog, medan is_file
returnerar om argumentet är en fil. Använd file_exists
att kontrollera om det är antingen.
$dir = "/this/is/a/directory";
$file = "/this/is/a/file.txt";
echo is_dir($dir) ? "$dir is a directory" : "$dir is not a directory", PHP_EOL,
is_file($dir) ? "$dir is a file" : "$dir is not a file", PHP_EOL,
file_exists($dir) ? "$dir exists" : "$dir doesn't exist", PHP_EOL,
is_dir($file) ? "$file is a directory" : "$file is not a directory", PHP_EOL,
is_file($file) ? "$file is a file" : "$file is not a file", PHP_EOL,
file_exists($file) ? "$file exists" : "$file doesn't exist", PHP_EOL;
Detta ger:
/this/is/a/directory is a directory
/this/is/a/directory is not a file
/this/is/a/directory exists
/this/is/a/file.txt is not a directory
/this/is/a/file.txt is a file
/this/is/a/file.txt exists
Kontrollerar filtyp
Använd filetype
att kontrollera typen av fil, som kan vara:
-
fifo
-
char
-
dir
-
block
-
link
-
file
-
socket
-
unknown
Skickar filnamnet direkt till filetype
:
echo filetype("~"); // dir
Observera att filetype
returnerar falskt och utlöser en E_WARNING
om filen inte finns.
Kontrollera läsbarhet och skrivbarhet
Att is_writable
filnamnet till is_writable
och is_readable
funktionerna kontrollerar om filen är skrivbar respektive läsbar.
Funktionerna returnerar false
graciöst om filen inte finns.
Kontrollerar filåtkomst / ändra tid
Att använda filemtime
och fileatime
returnerar tidsstämpeln för den senaste ändringen eller åtkomsten till filen. Returvärdet är en Unix-tidsstämpel - se Arbeta med datum och tid för mer information.
echo "File was last modified on " . date("Y-m-d", filemtime("file.txt"));
echo "File was last accessed on " . date("Y-m-d", fileatime("file.txt"));
Hämta sökvägsdelar med filinfo
$fileToAnalyze = ('/var/www/image.png');
$filePathParts = pathinfo($fileToAnalyze);
echo '<pre>';
print_r($filePathParts);
echo '</pre>';
Detta exempel kommer att matas ut:
Array
(
[dirname] => /var/www
[basename] => image.png
[extension] => png
[filename] => image
)
Som kan användas som:
$filePathParts['dirname']
$filePathParts['basename']
$filePathParts['extension']
$filePathParts['filename']
Parameter | detaljer |
---|---|
$ PATH | Filens hela sökväg som ska analyseras |
$ alternativ | Ett av fyra tillgängliga alternativ [PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION eller PATHINFO_FILENAME] |
- Om ett alternativ (den andra parametern) inte passeras, returneras en associerande matris, annars returneras en sträng.
- Validerar inte att filen finns.
- Torkar bara strängen i delar. Ingen validering görs på filen (ingen mime-typkontroll, etc.)
- Tillägget är helt enkelt den sista utvidgningen av
$path
Sökvägen för filenimage.jpg.png
skulle vara.png
även om den tekniskt sett är en.jpg
fil. En fil utan tillägg kommer inte att returnera ett tilläggselement i matrisen.
Minimera minnesanvändningen när du hanterar stora filer
Om vi behöver analysera en stor fil, t.ex. en CSV som är mer än 10 Mbyte som innehåller miljoner rader, använder vissa file
eller file_get_contents
funktioner och slutar med att slå memory_limit
inställningen med
Tillåten minnestorlek på XXXXX byte uttömd
fel. Tänk på följande källa (top-1m.csv har exakt 1 miljon rader och är ungefär 22 Mbyte i storlek)
var_dump(memory_get_usage(true));
$arr = file('top-1m.csv');
var_dump(memory_get_usage(true));
Denna utgångar:
int(262144)
int(210501632)
eftersom tolkarna behövde hålla alla raderna i $arr
array, så den konsumerade ~ 200 Mbyte RAM. Observera att vi inte ens har gjort något med innehållet i matrisen.
Tänk nu på följande kod:
var_dump(memory_get_usage(true));
$index = 1;
if (($handle = fopen("top-1m.csv", "r")) !== FALSE) {
while (($row = fgetcsv($handle, 1000, ",")) !== FALSE) {
file_put_contents('top-1m-reversed.csv',$index . ',' . strrev($row[1]) . PHP_EOL, FILE_APPEND);
$index++;
}
fclose($handle);
}
var_dump(memory_get_usage(true));
vilka utgångar
int(262144)
int(262144)
så vi använder inte en enda extrabyte med minne, utan analyserar hela CSV-filen och sparar den i en annan fil som vänder värdet på den andra kolumnen. Det beror på att fgetcsv
bara läser en rad och $row
skrivs över i varje slinga.
Strömbaserad fil IO
Öppnar en ström
fopen
öppnar ett fopen
som kan användas med olika funktioner för att läsa, skriva, söka och andra funktioner ovanpå det. Detta värde är av resource
och kan inte vidarebefordras till andra trådar som fortsätter att fungera.
$f = fopen("errors.log", "a"); // Will try to open errors.log for writing
Den andra parametern är läget för filströmmen:
Läge | Beskrivning |
---|---|
r | Öppna i skrivskyddsläge, från början av filen |
r+ | Öppet för läsning och skrivning, från början av filen |
w | öppet för skrivning endast från början av filen. Om filen finns kommer den att tömma filen. Om det inte existerar kommer det att försöka skapa det. |
w+ | öppet för läsning och skrivning, från början av filen. Om filen finns kommer den att tömma filen. Om det inte existerar kommer det att försöka skapa det. |
a | öppna en fil för skrivning endast från slutet av filen. Om filen inte finns, kommer den att försöka skapa den |
a+ | öppna en fil för att läsa och skriva, från slutet av filen. Om filen inte finns, kommer den att försöka skapa den |
x | skapa och öppna en fil för skrivning. Om filen finns kommer fopen samtalet att misslyckas |
x+ | skapa och öppna en fil för läsning och skrivning. Om filen finns kommer fopen samtalet att misslyckas |
c | öppna filen endast för skrivning. Om filen inte finns kommer den att försöka skapa den. Det börjar skriva i början av filen, men kommer inte att tömma filen innan den skrivs |
c+ | öppna filen för att läsa och skriva. Om filen inte finns kommer den att försöka skapa den. Det börjar skriva i början av filen, men kommer inte att tömma filen innan den skrivs |
Att lägga till en t
bakom läget (t.ex. a+b
, wt
, etc.) i Windows kommer att översätta "\n"
radavslut till "\r\n"
när du arbetar med filen. Lägg till b
bakom läget om detta inte är avsett, särskilt om det är en binär fil.
PHP-applikationen bör stänga strömmar med fclose
när de inte längre används för att förhindra felet Too many open files
. Detta är särskilt viktigt i CLI-program, eftersom strömmarna endast stängs när körtiden stängs av - det innebär att det på webbservrar kanske inte är nödvändigt (men ändå borde det som en praxis för att förhindra resursläckage) att stänga strömmarna om du inte förväntar dig att processen ska köras under lång tid och inte kommer att öppna många strömmar.
Läsning
Användning av fread
läser det givna antalet byte från filpekaren eller tills en EOF uppfylls.
Läser linjer
Med fgets
läses filen tills en EOL har nåtts, eller den angivna längden läses.
Både fread
och fgets
flyttar filpekaren under läsning.
Läser allt som återstår
Med hjälp av stream_get_contents
kommer alla återstående byte i strömmen till en sträng och returneras.
Justera filmarkörens position
Ursprungligen efter att strömmen har öppnats är filpekaren i början av filen (eller i slutet, om läget a
används). Med hjälp av fseek
funktionen flyttas filpekaren till en ny position, relativt ett av tre värden:
-
SEEK_SET
: Detta är standardvärdet; filpositionförskjutningen kommer att vara relativt filens början. -
SEEK_CUR
:SEEK_CUR
kommer att vara relativt den aktuella positionen. -
SEEK_END
:SEEK_END
kommer att vara relativt filens slut. Att passera en negativ offset är den vanligaste användningen för detta värde; den kommer att flytta filpositionen till det angivna antalet byte före filens slut.
rewind
är en bekväm genväg för fseek($fh, 0, SEEK_SET)
.
Att använda ftell
visar ftell
absoluta position.
Exempelvis läser följande skript över de första 10 byte, läser de nästa 10 byte, hoppar över 10 byte, läser de nästa 10 byte och sedan de 10 senaste byte i file.txt:
$fh = fopen("file.txt", "rb");
fseek($fh, 10); // start at offset 10
echo fread($fh, 10); // reads 10 bytes
fseek($fh, 10, SEEK_CUR); // skip 10 bytes
echo fread($fh, 10); // read 10 bytes
fseek($fh, -10, SEEK_END); // skip to 10 bytes before EOF
echo fread($fh, 10); // read 10 bytes
fclose($fh);
Skrivning
Med hjälp av fwrite
skriver du den fwrite
strängen till filen från och med den aktuella filpekaren.
fwrite($fh, "Some text here\n");
Flytta och kopiera filer och kataloger
Kopierar filer
copy
kopierar källfilen i det första argumentet till destinationen i det andra argumentet. Den lösta destinationen måste finnas i en katalog som redan är skapad.
if (copy('test.txt', 'dest.txt')) {
echo 'File has been copied successfully';
} else {
echo 'Failed to copy file to destination given.'
}
Kopiering av kataloger, med rekursion
Kopiering av kataloger liknar ganska mycket som att ta bort kataloger, förutom att för filer copy
istället för unlink
används, medan för kataloger används mkdir
istället för rmdir
, i början istället för att vara i slutet av funktionen.
function recurse_delete_dir(string $src, string $dest) : int {
$count = 0;
// ensure that $src and $dest end with a slash so that we can concatenate it with the filenames directly
$src = rtrim($dest, "/\\") . "/";
$dest = rtrim($dest, "/\\") . "/";
// use dir() to list files
$list = dir($src);
// create $dest if it does not already exist
@mkdir($dest);
// store the next file name to $file. if $file is false, that's all -- end the loop.
while(($file = $list->read()) !== false) {
if($file === "." || $file === "..") continue;
if(is_file($src . $file)) {
copy($src . $file, $dest . $file);
$count++;
} elseif(is_dir($src . $file)) {
$count += recurse_copy_dir($src . $file, $dest . $file);
}
}
return $count;
}
Döpa / Moving
Byt namn på / flytta filer och kataloger är mycket enklare. Hela kataloger kan flyttas eller byta namn på i ett enda samtal med hjälp av rename
.
rename("~/file.txt", "~/file.html");
rename("~/dir", "~/old_dir");
rename("~/dir/file.txt", "~/dir2/file.txt");