string|false fread ( resource $handle , int $length )
| 参数 | 描述 |
|---|---|
handle |
文件指针资源,通常由fopen()函数创建 |
length |
要读取的最大字节数 |
false<?php
// 创建测试文件
file_put_contents('test.txt', 'Hello, World! This is a test file.');
// 以只读模式打开文件
$handle = fopen('test.txt', 'r');
if ($handle === false) {
die('无法打开文件');
}
// 读取前5个字节
$content = fread($handle, 5);
echo "前5个字节: " . htmlspecialchars($content) . "<br>";
// 继续读取10个字节
$content = fread($handle, 10);
echo "接下来的10个字节: " . htmlspecialchars($content) . "<br>";
// 读取剩余所有内容
$remaining = fread($handle, filesize('test.txt'));
echo "剩余内容: " . htmlspecialchars($remaining) . "<br>";
fclose($handle);
?>
<?php
// 方法1:使用fread()读取整个文件
function readEntireFile_fread($filename) {
$handle = fopen($filename, 'r');
if (!$handle) return false;
// 获取文件大小
$filesize = filesize($filename);
if ($filesize === 0) {
fclose($handle);
return '';
}
// 读取整个文件
$content = fread($handle, $filesize);
fclose($handle);
return $content;
}
// 方法2:使用file_get_contents()读取整个文件
function readEntireFile_filegetcontents($filename) {
return file_get_contents($filename);
}
// 测试两种方法
$filename = 'example.txt';
file_put_contents($filename, str_repeat('A', 1000)); // 创建1KB的测试文件
$start1 = microtime(true);
$content1 = readEntireFile_fread($filename);
$time1 = microtime(true) - $start1;
$start2 = microtime(true);
$content2 = readEntireFile_filegetcontents($filename);
$time2 = microtime(true) - $start2;
echo "fread()方法读取时间: " . number_format($time1, 6) . " 秒<br>";
echo "file_get_contents()方法读取时间: " . number_format($time2, 6) . " 秒<br>";
echo "两种方法读取内容是否相同: " . ($content1 === $content2 ? '是' : '否') . "<br>";
// 清理测试文件
unlink($filename);
?>
<?php
// 创建二进制文件
$binaryData = pack('C*',
0x48, 0x65, 0x6C, 0x6C, 0x6F, // Hello
0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 // World
);
file_put_contents('binary.dat', $binaryData);
// 以二进制模式读取
$handle = fopen('binary.dat', 'rb'); // 注意:'rb'表示二进制只读模式
if ($handle) {
// 读取整个文件
$content = fread($handle, filesize('binary.dat'));
fclose($handle);
// 显示二进制内容
echo "二进制文件内容(十六进制): ";
for ($i = 0; $i < strlen($content); $i++) {
echo sprintf('%02X ', ord($content[$i]));
}
echo "<br>";
echo "转换为字符串: " . htmlspecialchars($content) . "<br>";
// 读取特定字节
$handle = fopen('binary.dat', 'rb');
$first5 = fread($handle, 5);
echo "前5个字节: " . htmlspecialchars($first5) . "<br>";
fclose($handle);
}
// 读取图片文件的二进制头
function getImageHeader($filename) {
if (!file_exists($filename)) {
return false;
}
$handle = fopen($filename, 'rb');
if (!$handle) return false;
// 读取前4个字节(足够识别大多数图片格式)
$header = fread($handle, 4);
fclose($handle);
return $header;
}
// 测试读取图片头
$header = getImageHeader('example.jpg');
if ($header !== false) {
echo "<br>图片文件头: ";
for ($i = 0; $i < strlen($header); $i++) {
echo sprintf('%02X ', ord($header[$i]));
}
}
?>
<?php
// 高效读取大文件的函数
function readLargeFile($filename, $chunkSize = 8192) {
$handle = fopen($filename, 'r');
if (!$handle) {
throw new Exception("无法打开文件: $filename");
}
// 使用生成器,避免一次性加载整个文件到内存
while (!feof($handle)) {
$chunk = fread($handle, $chunkSize);
if ($chunk !== false) {
yield $chunk;
}
}
fclose($handle);
}
// 使用示例:统计大文件中的单词数量
function countWordsInLargeFile($filename) {
$wordCount = 0;
$buffer = '';
foreach (readLargeFile($filename, 4096) as $chunk) {
$buffer .= $chunk;
// 处理缓冲区中的完整单词
$lastSpace = strrpos($buffer, ' ');
if ($lastSpace !== false) {
$toProcess = substr($buffer, 0, $lastSpace + 1);
$wordCount += str_word_count($toProcess);
$buffer = substr($buffer, $lastSpace + 1);
}
}
// 处理剩余的缓冲区内容
if (!empty($buffer)) {
$wordCount += str_word_count($buffer);
}
return $wordCount;
}
// 创建大测试文件
$largeFile = 'large_file.txt';
if (!file_exists($largeFile)) {
$handle = fopen($largeFile, 'w');
for ($i = 0; $i < 10000; $i++) {
fwrite($handle, "This is line $i with some words. ");
}
fclose($handle);
}
// 统计单词数量
$count = countWordsInLargeFile($largeFile);
echo "大文件中的单词数量: $count<br>";
echo "文件大小: " . number_format(filesize($largeFile)) . " 字节<br>";
// 清理测试文件(可选)
// unlink($largeFile);
?>
<?php
class SafeFileReader {
private $handle = null;
private $filename;
private $mode;
private $position = 0;
/**
* 打开文件
*/
public function open($filename, $mode = 'r') {
// 验证文件名安全性
if (!$this->validateFilename($filename)) {
throw new Exception("无效或危险的文件名");
}
// 验证文件存在性
if (!file_exists($filename)) {
throw new Exception("文件不存在: $filename");
}
$this->filename = $filename;
$this->mode = $mode;
$this->handle = fopen($filename, $mode);
if (!$this->handle) {
throw new Exception("无法打开文件: $filename");
}
return $this;
}
/**
* 读取指定长度的数据
*/
public function read($length) {
if (!$this->handle) {
throw new Exception("文件未打开");
}
$data = fread($this->handle, $length);
if ($data !== false) {
$this->position += strlen($data);
}
return $data;
}
/**
* 读取一行
*/
public function readLine() {
if (!$this->handle) {
throw new Exception("文件未打开");
}
$line = fgets($this->handle);
if ($line !== false) {
$this->position += strlen($line);
}
return $line;
}
/**
* 读取所有内容
*/
public function readAll() {
if (!$this->handle) {
throw new Exception("文件未打开");
}
// 保存当前位置
$currentPos = ftell($this->handle);
// 移动到文件开头
rewind($this->handle);
// 读取所有内容
$content = fread($this->handle, filesize($this->filename));
// 恢复位置
fseek($this->handle, $currentPos);
return $content;
}
/**
* 设置读取位置
*/
public function seek($offset, $whence = SEEK_SET) {
if (!$this->handle) {
throw new Exception("文件未打开");
}
$result = fseek($this->handle, $offset, $whence);
if ($result === 0) {
$this->position = ftell($this->handle);
}
return $result;
}
/**
* 获取当前位置
*/
public function getPosition() {
return $this->position;
}
/**
* 获取文件大小
*/
public function getFileSize() {
return file_exists($this->filename) ? filesize($this->filename) : 0;
}
/**
* 关闭文件
*/
public function close() {
if ($this->handle) {
fclose($this->handle);
$this->handle = null;
}
return $this;
}
/**
* 验证文件名安全性
*/
private function validateFilename($filename) {
// 防止目录遍历攻击
if (strpos($filename, '../') !== false || strpos($filename, '..\\') !== false) {
return false;
}
// 防止空字节攻击
if (strpos($filename, "\0") !== false) {
return false;
}
// 限制文件类型(可选)
$allowedExtensions = ['txt', 'log', 'csv', 'json', 'xml'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowedExtensions)) {
return false;
}
return true;
}
public function __destruct() {
$this->close();
}
}
// 使用示例
try {
// 创建测试文件
file_put_contents('test_data.txt', "Line 1\nLine 2\nLine 3\n");
// 使用SafeFileReader
$reader = new SafeFileReader();
$reader->open('test_data.txt');
echo "文件大小: " . $reader->getFileSize() . " 字节<br>";
// 读取第一行
echo "第一行: " . htmlspecialchars($reader->readLine()) . "<br>";
// 读取接下来的10个字节
echo "接下来10字节: " . htmlspecialchars($reader->read(10)) . "<br>";
// 获取当前位置
echo "当前位置: " . $reader->getPosition() . "<br>";
// 读取剩余所有内容
echo "剩余内容: " . htmlspecialchars($reader->readAll()) . "<br>";
$reader->close();
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
| 特性 | fread() | file_get_contents() |
|---|---|---|
| 使用方式 | 需要先打开文件句柄 | 直接传入文件名 |
| 控制粒度 | 可以精确控制读取位置和长度 | 只能读取整个文件 |
| 内存使用 | 可以分块读取,适合大文件 | 一次性加载整个文件到内存 |
| 性能 | 对于大文件更优(分块读取) | 对于小文件更优(单次调用) |
| 适用场景 | 大文件处理、二进制文件、需要精确控制时 | 小文件读取、配置文件、简单文本文件 |
读取INI、JSON、XML等配置文件,可以按需读取特定部分。
处理图片、音频、视频等二进制文件,读取文件头或特定数据块。
分析大型日志文件,分块读取避免内存溢出。
处理用户上传的文件,验证文件类型和内容。
fopen() - 打开文件或URLfclose() - 关闭一个已打开的文件指针fwrite() - 写入文件(fputs是其别名)fgets() - 从文件指针中读取一行feof() - 测试文件指针是否到达文件末尾fseek() - 在文件指针中定位ftell() - 返回文件指针读/写的位置file_get_contents() - 将整个文件读入字符串