php 有很多文件处理函数
file_get_contents 读取文件中的内容返回字符串。读取失败返回false。
$contents = file_get_contents('C:/private/filetest01.txt'); if ($contents === false) { echo 'Sorry, there was a problem reading the file.'; } else { // convert contents to uppercase and display echo strtoupper($contents); }
为什么不用if(!$content)
The reason I haven’t used that shortcut here is because the external file might be empty, or you might want it to store a number. As explained in “The truth according to PHP” in Chapter 3, an empty string and 0 also equate to false. So, in this case, I’ve used the identical operator (three equal signs), which ensures that both
the value and the data type are the same.
Text files can be used as a flat-file database—where each record is stored on a separate line, with a tab, comma, or other delimiter between each field (see http://en.wikipedia.org/ wiki/Flat_file_database). When handling this sort of file, it’s more convenient to store each line individually in an array ready for processing with a loop. The PHP file() function builds the array automatically. 下面的是文件内容。左为name 有为password
david, codeslave
chris, bigboss
file()函数,会自动读入每行来建立一个数组:
<?php $textfile = 'C:/private/filetest03.txt'; if (file_exists($textfile) && is_readable($textfile)) { // read the file into an array called $users $users = file($textfile); // loop through the array to process each line for ($i = 0; $i < count($users); $i++) { // separate each element and store in a temporary array $tmp = explode(', ', $users[$i]); // assign each element of the temporary array to a named array key $users[$i] = array('name' => $tmp[0], 'password' => rtrim($tmp[1])); } } else { echo "Can't open $textfile"; } ?> <pre> <?php print_r($users); ?> </pre>
注意这里:
'password' => rtrim($tmp[1]));
If a line ends in a new line character, the file() function doesn’t remove it, so you need to do it yourself.
每行的换行符必须要手动移去。
Opening and closing files for read/write operations
fopen(): Opens a file
fgets(): Reads the contents of a file, normally one line at a time
fread(): Reads a specified amount of a file
fwrite(): Writes to a file
feof(): Determines whether the end of the file has been reached
rewind(): Moves an internal pointer back to the top of the file
fclose(): Closes a file
The fopen() function returns a reference to the open file, which can then be used with any of the other read/write functions. So, this is how you would open a text file for reading:
$file = fopen('C:/private/filetest03.txt', 'r');
Thereafter, you pass $file as the argument to other functions, such as fgets(), feof(), and fclose().
用fopen读取文件:
<?php // store the pathname of the file $filename = 'C:/private/filetest03.txt'; // open the file in read-only mode $file = fopen($filename, 'r'); // read the file and store its contents $contents = fread($file, filesize($filename)); // close the file fclose($file); // display the contents echo nl2br($contents); ?>
string fread ( resource $handle
, int $length
) reads up to length
bytes from the file pointer referenced by handle
.
The nl2br() function in the final line converts new line characters to XHTML <br /> tags.
echo ("foo isn't \n bar"); \n根本没有换行,html中换行是<br/>
nl2br Returns string
with '<br />' or '<br>' inserted before all newlines (\r\n, \n\r, \n and \r).
<?php echo nl2br("foo isn't\n bar"); ?>
输出:
foo isn't<br /> bar
The other way to read the contents of a file with fopen() is to use the fgets() function, which retrieves one line at a time. This means that you need to use a while loop inUSING PHP TO MANAGE FILES combination with feof() to read right through to the end of the file. This is done by replacing this line
$contents = fread($file, filesize($filename));
with this (the full script is in fopen_readloop.php) // create variable to store the contents $contents = ''; // loop through each line until end of file while (!feof($file)) { // retrieve next line, and add to $contents $contents .= fgets($file); }
写文件:
<?php // if the form has been submitted, process the input text if (array_key_exists('putContents', $_POST)) { // strip backslashes from the input text and save to shorter variable $contents = get_magic_quotes_gpc() ? ➥ stripslashes($_POST['contents']) : $_POST['contents']; // open the file in write-only mode $file = fopen('C:/private/filetest04.txt', 'w'); // write the contents fwrite($file, $contents); // close the file fclose($file); } ?>
form id="writeFile" name="writeFile" method="post" action=""> <p> <label for="contents">Write this to file:</label> <textarea name="contents" cols="40" rows="6" id="contents"></textarea> </p> <p> <input name="putContents" type="submit" id="putContents" value="Write to file" /> </p> </form>
fputs()和fwrite()是同义的,功能都是一样的。
我们上面fopen()打开模式是w,以前的文本会被覆盖 掉。
Appending content with fopen()
// open the file in append mode $file = fopen('C:/private/filetest04.txt', 'a'); // write the contents after inserting new line fwrite($file, "\r\n$contents"); // close the file fclose($file);
Notice that I have enclosed $contents in double quotes and preceded it by carriage return and new line
characters (\r\n). This makes sure that the new content is added on a fresh line. When using this on Mac
OS X or a Linux server, omit the carriage return, and use this instead:
fwrite($file, "\n$contents");
Writing a new file with fopen()
Although it can be useful to have a file created automatically with the same name, it may be exactly the opposite of what you want. To make sure you’re not overwriting an existing file, you can use fopen() with x mode.
'x' Create and open for writing only; place the file pointer at the beginning of the file. If the file already exists, the fopen() call will fail by returning FALSE
and generating an error of level E_WARNING
.
即同一文件只能写一次。
Moving the internal pointer
Since reading and writing operations always start wherever the internal pointer happens to be, you normally want it to be at the beginning of the file for reading, and at the end of the file for writing.
To move the pointer to the beginning of a file Pass the reference to the open file to rewind() like this:
rewind($file); 倒回
To move the pointer to the end of a file
This is a little more complex. You need to use fseek(), which moves the pointer to a location specified by an offset and a PHP constant. The constant that represents the end of the file is SEEK_END, so an offset of 0 bytes places the pointer where you want it. You also need to pass fseek() a reference to the open file,
so all three arguments together look like this:
fseek($file, 0, SEEK_END);
Exploring the file system
PHP’s file system functions can also open directories (folders) and inspect their contents. From a web designer’s viewpoint, the most practical applications of this are building a drop-down menu of files and creating a unique name for a new file.
array scandir ( string $directory
[, int $sorting_order
= SCANDIR_SORT_ASCENDING [, resource $context
]] )
List files and directories inside the specified path。
Opening a directory to inspect its contents
// open the directory $folder = opendir('../images'); // initialize an array to store the contents $files = array(); // loop through the directory while (false !== ($item = readdir($folder))) { $files[] = $item; } // close it closedir($folder);
The readdir() function gets one item at a time and uses an internal pointer in the same
way as the functions used with fopen(). To build a list of the directory’s entire contents,
you need to use a while loop and store each result in an array. The condition for the loop
is contained in the following line:
while (false !== ($item = readdir($folder))) {
The readdir() function returns false when it can find no more items, so to prevent the
loop from coming to a premature end if it encounters an item named 0, for example, you
need to use false with the nonidentical operator (!==).
Each time the while loop runs, $item stores the name of the next file or folder, which is
then added to the $files array. Using this trio of functions isn’t difficult, but the one-line
scandir() is much simpler.
string readdir ( resource dir_handle )
返回目录中下一个文件的文件名。文件名以在文件系统中的排序返回。
请留意下面例子中检查 readdir() 返回值的风格。我们明确地测试返回值是否全等于(值和类型都相同 - 更多信息参见比较运算符)FALSE,否则任何目录项的名称求值为 FALSE 的都会导致循环停止(例如一个目录名为“0”)。
注意意 readdir() 将会返回 . 和 .. 条目。如果不想要它们,只要过滤掉即可
列出当前目录的所有文件并去掉 . 和 ..
<?php if ($handle = opendir('.')) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { echo "$file\n"; } } closedir($handle); } ?>
个人笔记:
opendir只支持本地目录,不支持http:.// 目录 ,如果报错: failed to open dir: not implemented 这是这个问题,
用相对目录会好一点。
Building a drop-down menu of files
<form id="form1" name="form1" method="post" action=""> <select name="pix" id="pix"> <option value="">Select an image</option> <?php include('../includes/buildFileList5.php'); buildFileList5('../images'); ?> </select> </form>
<?php function buildFileList5($theFolder) { // Execute code if the folder can be opened, or fail silently if ($contents = @ scandir($theFolder)) { // initialize an array for matching files $found = array(); // Create an array of file types $fileTypes = array('jpg','jpeg','gif','png'); // Traverse the folder, and add filename to $found array if type matches $found = array(); foreach ($contents as $item) { $fileInfo = pathinfo($item); if (array_key_exists('extension', $fileInfo) && in_array($fileInfo['extension'],$fileTypes)) { $found[] = $item; } } // Check the $found array is not empty if ($found) { // Sort in natural, case-insensitive order, and populate menu natcasesort($found); foreach ($found as $filename) { echo "<option value='$filename'>$filename</option>\n"; } } } } ?>
After the folder has been opened, each item is
passed to a PHP function called pathinfo(), which returns an associative array with the
following elements:
dirname: The name of the directory (folder)
basename: The filename, including extension (or just the name if it’s a directory)
extension: The filename extension (not returned for a directory)
<?php $path_parts = pathinfo('/www/htdocs/inc/lib.inc.php'); echo $path_parts['dirname'], "\n"; echo $path_parts['basename'], "\n"; echo $path_parts['extension'], "\n"; echo $path_parts['filename'], "\n"; // since PHP 5.2.0 ?>
/www/htdocs/inc lib.inc.php php lib.inc
对于一个目录来说,extension是没有的。
Because the extension element is not returned for a directory, you need to use
array_key_exists() before attempting to check its value. The second half of the conditional
statement in line 12 uses in_array() to see if the value of extension matches one
of the file types that you’re looking for. It there’s a match, the filename is added to the
$found array. It’s then just a case of building the <option> elements with a foreach loop,
but to add a user-friendly touch, the $found array is first passed to the natcasesort()
function, which sorts the filenames in a case-insensitive order.
Automatically creating the next file in a series
In the last chapter I showed you how to create a unique filename by adding a timestamp
or using the date() function to generate the date and time in human-readable format. It
works, but is hardly ideal. A numbered series, such as file01.txt, file02.txt, and so on,
is usually better. The problem is that a PHP script has no way to keep track of a series of
numbers between requests to the server. However, by inspecting the contents of a directory,
you can use pattern matching to find the highest existing number, and assign the next
one in the series.
I’ve turned this into a function called getNextFilename()
The function takes the following three arguments:
The pathname of the directory where you want the new file to be created
The prefix of the filename, which must consist of alphanumeric characters only
The filename extension (without a leading period)
<?php // if the form has been submitted, process the input text if (array_key_exists('putContents', $_POST)) { include('../includes/getNextFilename5.php'); // use getNextFilename4.php if running on a PHP 4 server // strip backslashes from the input text and save to shorter variable $contents = get_magic_quotes_gpc() ? stripslashes($_POST['contents']) : $_POST['contents']; $dir = 'C:/private'; $filename = getNextFilename5($dir, 'comment', 'txt'); // use getNextFilename4() if running on PHP 4 if ($filename) { // create a file ready for writing only if it doesn't already exist if ($file = @ fopen("$dir/$filename", 'x')) { // write the contents fwrite($file, $contents); // close the file fclose($file); $result = "$filename created"; } else { $result = 'Cannot create file'; } } else { $result = 'Invalid folder or filename'; } } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Create series of consecutively numbered files</title> </head> <body> <?php if (isset($result)) { echo "<p>$result</p>"; } ?> <form id="writeFile" name="writeFile" method="post" action=""> <p> <label for="contents">Write this to file:</label> <textarea name="contents" cols="40" rows="6" id="contents"></textarea> </p> <p> <input name="putContents" type="submit" id="putContents" value="Write to file" /> </p> </form> </body> </html>
<?php function getNextFilename5($dir, $prefix, $type) { // run some security checks on the arguments supplied if (!is_dir($dir)) return false; if (!preg_match('/^[-._a-z0-9]+$/i', $prefix)) return false; $permittedTypes = array('txt', 'doc', 'pdf', 'jpg', 'jpeg', 'gif', 'png'); if (!in_array(strtolower($type), $permittedTypes)) return false; // if the checks are OK, get an array of the directory contents $existing = scandir($dir); // create a search pattern for filenames that match the prefix and type $pattern = '/^'.$prefix.'(\d+)\.'.$type.'$/i'; $nums = array(); // loop through the directory // get the numbers from all files that match the pattern foreach ($existing as $file) { if (preg_match($pattern, $file, $m)) { $nums[] = intval($m[1]); } } // find the highest number and increase it by 1 // if no file yet created, assign it number 1 $next = $nums ? max($nums)+1 : 1; // calculate how many zeros to prefix the number with if ($next < 10) { $zeros = '00'; } elseif ($next < 100) { $zeros = '0'; } else { $zeros = '' ; } // return the next filename in the series return "{$prefix}{$zeros}{$next}.{$type}"; } ?>
Opening remote data sources
PHP can open publicly available files on other servers just as easily as on the same server.
This is particularly useful for accessing XML files or news feeds. All that you need to do is
pass the URL as an argument to the function. Unfortunately, as noted earlier, many hosting
companies disable the allow_url_fopen setting in PHP. One way to get around this is
to use a socket connection instead.
To create a socket connection, use the fsockopen() function, which takes the following
five arguments:
此处暂时省略。