如果您正在读取的文件是 CSV 格式,请不要使用 file(),请使用 fgetcsv()。file() 将根据它找到的每个换行符拆分文件,即使换行符出现在字段内(即引号内)。
(PHP 4, PHP 5, PHP 7, PHP 8)
file — 将整个文件读入数组
filename
文件路径。
flags
可选参数 flags
可以是以下常量之一或多个
FILE_USE_INCLUDE_PATH
FILE_IGNORE_NEW_LINES
FILE_SKIP_EMPTY_LINES
FILE_NO_DEFAULT_CONTEXT
context
返回一个包含文件内容的数组。数组的每个元素对应于文件中的每一行,换行符仍然保留。如果失败,file() 返回 false
。
注意:
结果数组中的每一行都将包含行尾,除非使用
FILE_IGNORE_NEW_LINES
。
注意: 如果 PHP 在读取在 Macintosh 计算机上或由其创建的文件时没有正确识别行尾,则启用 auto_detect_line_endings 运行时配置选项可能有助于解决此问题。
如果文件不存在,则会发出 E_WARNING
级别的错误。
示例 #1 file() 示例
<?php
// 将文件读入数组。在此示例中,我们将通过 HTTP 获取 URL 的 HTML 源代码。
$lines = file('http://www.example.com/');
// 遍历数组,将 HTML 源代码显示为 HTML 源代码;并显示行号。
foreach ($lines as $line_num => $line) {
echo "Line #<b>{$line_num}</b> : " . htmlspecialchars($line) . "<br />\n";
}
// 使用可选的 flags 参数
$trimmed = file('somefile.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
?>
在使用 SSL 时,Microsoft IIS 会通过在未发送 close_notify
指示的情况下关闭连接来违反协议。当您到达数据末尾时,PHP 会将其报告为“SSL:致命协议错误”。为了解决此问题,应将 error_reporting 的值降低到不包含警告的级别。当您使用 https://
包装器打开流时,PHP 可以检测到有缺陷的 IIS 服务器软件,并将抑制警告。当使用 fsockopen() 创建 ssl://
套接字时,开发人员负责检测和抑制此警告。
如果您正在读取的文件是 CSV 格式,请不要使用 file(),请使用 fgetcsv()。file() 将根据它找到的每个换行符拆分文件,即使换行符出现在字段内(即引号内)。
要写入文件的所有行,换句话说,要逐行读取文件,您可以这样编写代码
<?php
$names=file('name.txt');
// 检查行数
echo count($names).'<br>';
foreach($names as $name)
{
echo $name.'<br>';
}
?>
此示例非常基础,可以帮助您理解它的工作原理。希望它能帮助许多初学者。
此致,
Bingo
这可能很明显,但我花了很长时间才弄清楚我做错了什么。所以我想分享一下。我在我的“c:\”驱动器上有一个文件。如何用 file() 打开它?
不要忘记反斜杠是特殊的,您必须对其进行“转义”,即“\\”
<?php
$lines = file("C:\\Documents and Settings\\myfile.txt");
foreach($lines as $line)
{
echo($line);
}
?>
希望这有帮助……
从 CSV 数据(文件)读入具有命名键的数组
… 有或没有第一行 = 标题(键)
(查看函数调用的第四个参数是 true / false)
<?php
// --------------------------------------------------------------
function csv_in_array($url,$delm=";",$encl="\"",$head=false) {
$csvxrow = file($url); // ---- csv rows to array ----
$csvxrow[0] = chop($csvxrow[0]);
$csvxrow[0] = str_replace($encl,'',$csvxrow[0]);
$keydata = explode($delm,$csvxrow[0]);
$keynumb = count($keydata);
if ($head === true) {
$anzdata = count($csvxrow);
$z=0;
for($x=1; $x<$anzdata; $x++) {
$csvxrow[$x] = chop($csvxrow[$x]);
$csvxrow[$x] = str_replace($encl,'',$csvxrow[$x]);
$csv_data[$x] = explode($delm,$csvxrow[$x]);
$i=0;
foreach($keydata as $key) {
$out[$z][$key] = $csv_data[$x][$i];
$i++;
}
$z++;
}
}
else {
$i=0;
foreach($csvxrow as $item) {
$item = chop($item);
$item = str_replace($encl,'',$item);
$csv_data = explode($delm,$item);
for ($y=0; $y<$keynumb; $y++) {
$out[$i][$y] = $csv_data[$y];
}
$i++;
}
}
return $out;
}
// --------------------------------------------------------------
?>
使用 4 个参数调用函数
(1) = 包含 CSV 数据的文件(URL 或字符串)
(2) = 列分隔符(例如:; 或 | 或 , ...)
(3) = 值包围符(例如:' 或 " 或 ^ 或 ...)
(4) = 是否包含第一行作为标题(true/false)
<?php
// ----- 调用 ------
$csvdata = csv_in_array( $yourcsvfile, ";", "\"", true );
// -----------------
// ----- 查看 ------
echo "<pre>\r\n";
print_r($csvdata);
echo "</pre>\r\n";
// -----------------
?>
PS:也可以参考:https://php.net/manual/de/function.fgetcsv.php 将 CSV 数据读入数组
... 以及其他文件处理方法
^
请注意,使用 file() 来计数行可能会导致服务器出现 OOM,因为它会将所有行分配到一个数组中。
如果您处理的是可能包含数千行的文件,SplFileObject 可能是一个更好的选择,只需稍作修改就可以得到相同的结果。
从 PHP 5.6 开始,如果引用的是没有有效 SSL 证书的源 URL,则 file()、file_get_contents() 和 fopen() 函数将返回 false。可能在您的开发环境中经常遇到这种情况,这会让您抓狂。
您需要创建一个流上下文,并将其作为参数提供给各种文件操作,告诉它忽略无效的 SSL 证书。
$args = array("ssl"=>array("verify_peer"=>false,"verify_peer_name"=>false),"http"=>array('timeout' => 60, 'user_agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/3.0.0.1'));
$context = stream_context_create($args);
$httpfile = file($url, false, $context);
此说明适用于 Windows 下的 PHP 5.1.6(尽管可能适用于其他版本)。
看起来 'FILE_IGNORE_NEW_LINES' 标志在读取 Windows 风格的文本文件(即行以 '\r\n' 结尾的文件)时不能正确删除换行符。
解决方案:始终优先使用 'rtrim()' 而不是 'FILE_IGNORE_NEW_LINES'。
(“file() 处理 UTF-16 存在问题”是错误的。此内容已更新。
前者可能会错过字符串的最后一行。)
file() 在处理
带 BOM 或不带 BOM 的 UTF-16 时似乎存在问题。
file() 可能会将 "\n"=LF (0A) 视为行结束符。
因此,不仅 "000A",而且 "010A, 020A,...,FE0A, FF0A,..."
都被视为行结束符。
此外,file() 在 UTF-16LE 中会导致严重问题。
file() 会丢失第一个 "0A"("0A00" 的前半部分)!
并且下一行以 "00" 开头("0A00" 的剩余部分)。
因此,第一行 "0A" 之后的行完全不同。
为了避免这种现象,
例如,在(php_script:UTF-8,file:UTF-16,行结束符为 "\r\n")的情况下,
<?php
mb_regex_encoding('UTF-16'); // 帮助 mb_ereg_..() 正确工作
$str = file_get_contents($file_path);
$to_encoding = 'UTF-16'; // 字符串的编码
$from_encoding = 'UTF-8'; // PHP_script 的编码
$pattern1 = mb_convert_encoding('[^\r]*\r\n', $to_encoding, $from_encoding);
mb_ereg_search_init($str, $pattern1);
while ($res = mb_ereg_search_regs()) {
$file[] = $res[0];
}
$pattern2 = mb_convert_encoding('\A.*\r\n(.*)\z', $to_encoding, $from_encoding);
mb_ereg($pattern2, $str, $match);
$file[] = $match[1];
?>
而不是
$file = file($file_path);
如果行结束符为 "\n",
$pattern1 = mb_convert_encoding('[^\n]*\n', $to_encoding, $from_encoding);
注意:现在 file() 是二进制安全的,它比以前“慢”得多。如果您打算读取大型文件,使用 fgets() 而不是 file() 可能会有所帮助。例如
<?php
$fd = fopen ("log_file.txt", "r");
while (!feof ($fd))
{
$buffer = fgets($fd, 4096);
$lines[] = $buffer;
}
fclose ($fd);
?>
结果数组是 $lines。
我测试了一个包含 200,000 行的文件。使用 fgets() 耗时几秒,而使用 file() 则耗时几分钟。
如果您在尝试使用 file() 或 fopen() 访问另一个服务器上的文件时收到“无法打开流:权限被拒绝”错误。检查您的主机是否实施了任何阻止出站连接的防火墙限制。我的主机 Aplus.net 就是这种情况。
使用 if ( file(name.txt) ) 可能不足以测试文件是否已成功打开以供读取,因为文件可能是空的,在这种情况下返回的数组为空,因此请使用 !== 进行测试。例如:
$file_array = file('test.txt'); // 一个空文件
echo '<pre>';
if ( $file_array ) {
# 代码...
echo "成功\n";
} else {
# 代码...
echo "失败\n"; // 执行
}
if ( $file_array !== false ) {
# 代码...
echo "成功\n"; // 执行
} else {
# 代码...
echo "失败\n";
}
echo '</pre>';
结果
失败
成功
一位用户建议始终使用 rtrim,因为行尾与具有与服务器行尾不同的 EOL 的文件存在冲突。
但是,使用 rtrim 及其默认字符替换是一个糟糕的解决方案,因为它除了 '\r' 和 '\n' 字符外,还会删除所有空白。
以下是使用 rtrim 的一个好的解决方案
<?php
$line = rtrim($line, "\r\n") . PHP_EOL;
?>
这仅删除 EOL 字符,并用服务器的 EOL 字符替换,从而使 preg_* 在匹配 EOL ($) 时正常工作。
这是我的 CSV 转换器
支持标题并修剪所有字段
注意:标题不能为空!
<?php
function csv2array($file, $delim = ';', $encl = '"', $header = false) {
# 文件不存在
if(!file_exists($file))
return false;
# 将文件行读取到数组中
$file_lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
# 空文件
if($file_lines === array())
return NULL;
# 如果需要,读取标题
if($header === true) {
$line_header = array_shift($file_lines);
$array_header = array_map('trim', str_getcsv($line_header, $delim, $encl));
}
$out = NULL;
# 现在逐行(字符串)
foreach ($file_lines as $line) {
# 跳过空行
if(trim($line) === '')
continue;
# 将行转换为数组
$array_fields = array_map('trim', str_getcsv($line, $delim, $encl));
# 如果存在标题,将标题和字段组合为键 => 值
if($header === true)
$out[] = array_combine ($array_header, $array_fields);
else
$out[] = $array_fields;
}
return $out;
}
?>
使用 file() 读取大于 10 Mb 的大型文本文件会出现问题,因此您应该改为使用此方法。它速度慢得多,但工作正常。$lines 将返回包含所有行的数组。
<?php
$handle = @fopen('yourfile...', "r");
if ($handle) {
while (!feof($handle)) {
$lines[] = fgets($handle, 4096);
}
fclose($handle);
}
?>