Szukaj…


Składnia

  • int plik odczytu (ciąg $ nazwa_pliku [, bool $ use_include_path = false [, zasób $ kontekst]])

Parametry

Parametr Opis
Nazwa pliku Odczytywana nazwa pliku.
use_include_path Możesz użyć opcjonalnego drugiego parametru i ustawić go na PRAWDA, jeśli chcesz również wyszukać plik w ścieżce dołączania.
kontekst Zasób strumienia kontekstu.

Uwagi

Składnia nazwy pliku

Większość nazw plików przekazywanych do funkcji w tym temacie to:

  1. Struny w przyrodzie.
    • Nazwy plików można przekazywać bezpośrednio. Jeśli wartości innych typów są przekazywane, są one rzutowane na ciąg. Jest to szczególnie przydatne w SplFileInfo , która jest wartością w iteracji DirectoryIterator .
  2. Względny lub absolutny.
    • Mogą być absolutne. W systemach uniksowych ścieżki bezwzględne rozpoczynają się od / , np. /home/user/file.txt , podczas gdy w systemie Windows ścieżki bezwzględne zaczynają się od dysku, np. C:/Users/user/file.txt
    • Mogą być również względne, co zależy od wartości getcwd i może ulec zmianie przez chdir .
  3. Zaakceptuj protokoły.
    • Mogą zaczynać się od scheme:// aby określić opakowanie protokołu do zarządzania. Na przykład file_get_contents("http://example.com") pobiera treść z http://example.com .
  4. Kompatybilny z Slash.
    • Chociaż DIRECTORY_SEPARATOR w systemie Windows jest ukośnikiem odwrotnym, a system domyślnie zwraca ukośniki odwrotne dla ścieżek, programista może nadal używać / jako separatora katalogów. Dlatego w celu zachowania zgodności programiści mogą używać / jako separatorów katalogów we wszystkich systemach, ale należy pamiętać, że wartości zwracane przez funkcje (np. realpath ) mogą zawierać ukośniki odwrotne.

Usuwanie plików i katalogów

Usuwanie plików

Funkcja unlink usuwa pojedynczy plik i zwraca informację, czy operacja się powiodła.

$filename = '/path/to/file.txt';

if (file_exists($filename)) {
    $success = unlink($filename);
    
    if (!$success) {
         throw new Exception("Cannot delete $filename");
    }
}

Usuwanie katalogów z rekurencyjnym usuwaniem

Z drugiej strony katalogi powinny zostać usunięte za pomocą rmdir . Jednak ta funkcja usuwa tylko puste katalogi. Aby usunąć katalog z plikami, najpierw usuń pliki z katalogów. Jeśli katalog zawiera podkatalogi, może być wymagana rekursja .

Poniższy przykład skanuje pliki w katalogu, rekursywnie usuwa pliki członkowskie / katalogi i zwraca liczbę usuniętych plików (nie katalogów).

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;
}

Funkcje wygody

Raw bezpośrednie IO

file_get_contents i file_put_contents zapewniają możliwość odczytu / zapisu z / do pliku do / z łańcucha PHP w jednym wywołaniu.

file_put_contents można również używać z FILE_APPEND maski bitowej FILE_APPEND aby dołączyć do pliku zamiast go obcinać i zastępować. Można go użyć wraz z LOCK_EX aby uzyskać wyłączną blokadę pliku podczas pisania. Flagi maski bitowej można łączyć z | operator bitowy-LUB.

$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 jest przydatny do dołączania do plików dziennika, a LOCK_EX pomaga zapobiegać warunkom wyścigu zapisu plików z wielu procesów. Na przykład, aby zapisać do pliku dziennika o bieżącej sesji:

file_put_contents("logins.log", "{$_SESSION["username"]} logged in", FILE_APPEND | LOCK_EX);

CSV IO

fgetcsv($file, $length, $separator)

fgetcsv analizuje wiersz z sprawdzania otwartych plików dla pól csv. Zwraca pola CSV w tablicy w przypadku sukcesu lub FALSE w przypadku niepowodzenia.

Domyślnie będzie odczytywał tylko jedną linię pliku CSV.

$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

Wynik:

Array
(
    [0] => Kai Jim
    [1] => Refsnes
    [2] => Stavanger
    [3] => Norway
)
Array
(
    [0] => Hege,
)

Czytanie pliku bezpośrednio na standardowe wyjście

plik readfile kopiuje plik do bufora wyjściowego. readfile () nie stwarza żadnych problemów z pamięcią, nawet przy wysyłaniu dużych plików.

$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;
}

Lub ze wskaźnika pliku

Alternatywnie, aby wyszukać punkt w pliku i rozpocząć kopiowanie na standardowe wyjście, użyj zamiast tego fpassthru . W poniższym przykładzie ostatnie 1024 bajty są kopiowane na standardowe wyjście:

$fh = fopen("file.txt", "rb");
fseek($fh, -1024, SEEK_END); 
fpassthru($fh);

Odczytywanie pliku do tablicy

file zwraca wiersze w przekazanym pliku w tablicy. Każdy element tablicy odpowiada linii w pliku z nową linią nadal dołączoną.

print_r(file("test.txt"));

test.txt

Welcome to File handling
This is to test file handling

Wynik:

Array 
( 
    [0] => Welcome to File handling 
    [1] => This is to test file handling 
)

Uzyskiwanie informacji o pliku

Sprawdź, czy ścieżka jest katalogiem czy plikiem

Funkcja is_dir zwraca, czy argument jest katalogiem, a is_file zwraca, czy argument jest plikiem. Użyj file_exists aby sprawdzić, czy tak jest.

$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;

To daje:

/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

Sprawdzanie typu pliku

Użyj typu filetype aby sprawdzić typ pliku, którym może być:

  • fifo
  • char
  • dir
  • block
  • link
  • file
  • socket
  • unknown

Przekazywanie nazwy filetype bezpośrednio do typu filetype :

echo filetype("~"); // dir

Zauważ, że filetype zwraca wartość false i wyzwala E_WARNING jeśli plik nie istnieje.

Sprawdzanie czytelności i możliwości zapisu

Przekazywanie nazwy pliku do funkcji is_writable i is_readable sprawdza, czy plik jest odpowiednio zapisywalny lub czytelny.

Funkcje zwracają false wdzięcznie, jeśli plik nie istnieje.

Sprawdzanie czasu dostępu do pliku / modyfikacji

Użycie filemtime fileatime i fileatime zwraca znacznik czasu ostatniej modyfikacji lub dostępu do pliku. Zwracana wartość to uniksowy znacznik czasu - szczegółowe informacje można znaleźć w części Praca z datami i czasem .

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"));

Uzyskaj części ścieżki za pomocą fileinfo

$fileToAnalyze = ('/var/www/image.png');

$filePathParts = pathinfo($fileToAnalyze);

echo '<pre>';
   print_r($filePathParts);
echo '</pre>';

Ten przykład wyświetli:

Array
(
    [dirname] => /var/www
    [basename] => image.png
    [extension] => png
    [filename] => image
)

Które mogą być użyte jako:

$filePathParts['dirname']
$filePathParts['basename']
$filePathParts['extension']
$filePathParts['filename']
Parametr Detale
$ ścieżka Pełna ścieżka pliku do przeanalizowania
Opcja $ Jedna z czterech dostępnych opcji [PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION lub PATHINFO_FILENAME]
  • Jeśli opcja (drugi parametr) nie zostanie przekazana, zwracana jest tablica asocjacyjna, w przeciwnym razie zwracany jest łańcuch.
  • Nie sprawdza, czy plik istnieje.
  • Po prostu analizuje ciąg na części. W pliku nie przeprowadza się sprawdzania poprawności (bez sprawdzania typu MIME itp.)
  • Rozszerzenie jest po prostu ostatnim rozszerzeniem $path Ścieżka do pliku image.jpg.png to .png nawet jeśli technicznie jest to plik .jpg . Plik bez rozszerzenia nie zwróci elementu rozszerzenia w tablicy.

Minimalizuj zużycie pamięci podczas pracy z dużymi plikami

Jeśli musimy przeanalizować duży plik, np. Plik CSV o wielkości większej niż 10 MB, zawierający miliony wierszy, niektórzy używają funkcji file lub file_get_contents i kończą się naciśnięciem ustawienia memory_limit pomocą

Dozwolony rozmiar pamięci XXXXX bajtów wyczerpany

błąd. Rozważ następujące źródło (top-1m.csv ma dokładnie 1 milion wierszy i ma rozmiar około 22 Mb)

var_dump(memory_get_usage(true));
$arr = file('top-1m.csv');
var_dump(memory_get_usage(true));

To daje:

int(262144)
int(210501632) 

ponieważ interpreter musiał pomieścić wszystkie wiersze w tablicy $arr , więc zużył ~ 200 MB pamięci RAM. Zauważ, że nawet nie zrobiliśmy nic z zawartością tablicy.

Teraz rozważ następujący 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));

które wyjścia

int(262144)
int(262144)

więc nie używamy żadnego dodatkowego bajtu pamięci, ale analizujemy cały plik CSV i zapisujemy go w innym pliku odwracającym wartość drugiej kolumny. Jest tak, ponieważ fgetcsv czyta tylko jeden wiersz, a $row jest zastępowany w każdej pętli.

Plik IO oparty na strumieniu

Otwieranie strumienia

fopen otwiera uchwyt strumienia plików, który może być używany z różnymi funkcjami do czytania, pisania, wyszukiwania i innymi funkcjami na nim. Ta wartość jest typu resource i nie może być przekazana do innych wątków utrwalających jej funkcjonalność.

$f = fopen("errors.log", "a"); // Will try to open errors.log for writing

Drugi parametr to tryb strumienia plików:

Tryb Opis
r Otwórz w trybie tylko do odczytu, zaczynając od początku pliku
r+ Otwarty do czytania i pisania, zaczynając od początku pliku
w otwarte tylko do zapisu, zaczynając od początku pliku. Jeśli plik istnieje, spowoduje jego opróżnienie. Jeśli nie istnieje, spróbuje go utworzyć.
w+ otwarty do czytania i pisania, zaczynając od początku pliku. Jeśli plik istnieje, spowoduje jego opróżnienie. Jeśli nie istnieje, spróbuje go utworzyć.
a otwórz plik tylko do zapisu, zaczynając od końca pliku. Jeśli plik nie istnieje, spróbuje go utworzyć
a+ otwórz plik do odczytu i zapisu, zaczynając od końca pliku. Jeśli plik nie istnieje, spróbuje go utworzyć
x utwórz i otwórz plik tylko do zapisu. Jeśli plik istnieje, wywołanie fopen zakończy się niepowodzeniem
x+ utwórz i otwórz plik do odczytu i zapisu. Jeśli plik istnieje, wywołanie fopen zakończy się niepowodzeniem
c otwórz plik tylko do zapisu. Jeśli plik nie istnieje, spróbuje go utworzyć. Zacznie pisać na początku pliku, ale nie opróżni pliku przed zapisaniem
c+ otwórz plik do odczytu i zapisu. Jeśli plik nie istnieje, spróbuje go utworzyć. Zacznie pisać na początku pliku, ale nie opróżni pliku przed zapisaniem

Dodanie t poza trybem (np. a+b , wt itp.) W systemie Windows spowoduje przetłumaczenie zakończeń linii "\n" na "\r\n" podczas pracy z plikiem. Dodaj b za trybem, jeśli nie jest to zamierzone, zwłaszcza jeśli jest to plik binarny.

Aplikacja PHP powinna zamykać strumienie za pomocą fclose gdy nie są one już używane, aby zapobiec błędowi Too many open files . Jest to szczególnie ważne w programach CLI, ponieważ strumienie są zamykane tylko wtedy, gdy środowisko wykonawcze jest zamykane - oznacza to, że na serwerach internetowych może nie być konieczne (ale nadal powinno to być , w celu zapobiegania wyciekom zasobów), zamknięcie strumieni jeśli nie oczekujesz, że proces będzie działał przez długi czas i nie otworzy wielu strumieni.

Czytanie

Użycie fread spowoduje odczytanie podanej liczby bajtów ze wskaźnika pliku lub do momentu spełnienia EOF.

Czytanie wierszy

Korzystanie z fgets spowoduje odczytanie pliku do momentu osiągnięcia EOL lub odczytania podanej długości.

Zarówno fread jak i fgets przesuwają wskaźnik pliku podczas czytania.

Czytanie wszystkiego, co pozostało

Użycie stream_get_contents spowoduje, że wszystkie pozostałe bajty w strumieniu staną się ciągiem znaków i zwrócą go.

Dostosowywanie położenia wskaźnika pliku

Początkowo po otwarciu strumienia wskaźnik pliku znajduje się na początku pliku (lub na końcu, jeśli używany jest tryb a ). Użycie funkcji fseek spowoduje przeniesienie wskaźnika pliku do nowej pozycji względem jednej z trzech wartości:

  • SEEK_SET : Jest to wartość domyślna; przesunięcie pozycji pliku będzie względne względem początku pliku.
  • SEEK_CUR : Przesunięcie pozycji pliku będzie względem bieżącego położenia.
  • SEEK_END : Przesunięcie pozycji pliku będzie względne względem końca pliku. Przekazywanie ujemnego przesunięcia jest najczęstszym zastosowaniem tej wartości; przesunie pozycję pliku do określonej liczby bajtów przed końcem pliku.

rewind jest wygodnym skrótem fseek($fh, 0, SEEK_SET) .

Użycie ftell pokaże bezwzględną pozycję wskaźnika pliku.

Na przykład poniższy skrypt czyta pomija pierwsze 10 bajtów, odczytuje kolejne 10 bajtów, pomija 10 bajtów, odczytuje kolejne 10 bajtów, a następnie ostatnie 10 bajtów w pliku.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);

Pisanie

Za pomocą fwrite zapisuje podany ciąg do pliku, zaczynając od bieżącego wskaźnika pliku.

fwrite($fh, "Some text here\n");

Przenoszenie i kopiowanie plików i katalogów

Kopiowanie plików

copy kopiuje plik źródłowy z pierwszego argumentu do miejsca docelowego w drugim argumencie. Rozwiązany cel musi znajdować się w katalogu, który jest już utworzony.

if (copy('test.txt', 'dest.txt')) {
    echo 'File has been copied successfully';
} else {
    echo 'Failed to copy file to destination given.'
}

Kopiowanie katalogów z rekurencją

Kopiowanie katalogów jest bardzo podobne do usuwania katalogów, z tym wyjątkiem, że w przypadku plików używana jest copy zamiast unlink , natomiast w przypadku katalogów mkdir zamiast rmdir jest używany na początku zamiast na końcu funkcji.

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;
}

Zmiana nazwy / przenoszenie

Zmiana nazwy / przenoszenie plików i katalogów jest znacznie prostsze. Całe katalogi można przenosić lub zmieniać ich nazwy w jednym wywołaniu za pomocą funkcji rename .

  • rename("~/file.txt", "~/file.html");

  • rename("~/dir", "~/old_dir");

  • rename("~/dir/file.txt", "~/dir2/file.txt");



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow