【问题标题】:PHP read part of large CSV filePHP 读取大型 CSV 文件的一部分
【发布时间】:2016-09-26 08:46:39
【问题描述】:

我有一个大的 CSV 文件。由于内存问题(使用 MySQL),如果可能的话,我想一次只读取其中的一部分。

CSV 可能并不重要。重要的是它需要用新的线切割。

示例内容:

Some CSV content
that will break
on a line break

这可能是我的路径:

$path = 'path/to/my.csv';

在我看来,它的解决方案可能如下所示:

$csv_content1 = read_csv_file($path, 0, 100);
$csv_content2 = read_csv_file($path, 101, 200);
  1. 它读取第 0-100 行的原始内容。
  2. 它读取第 101-200 行的原始内容。

信息

  • 无需解析(只需拆分为内容)。
  • 该文件存在于我自己的服务器上。
  • 不要将整个文件读入内存。
  • 我希望能够在另一个时间进行第二次读取,而不是在同一次运行中。如果需要,我接受保存临时值,如指针。

我一直在尝试阅读其他主题,但没有找到与此问题完全匹配的内容。

也许其中一些可能会起作用?

  • SplFileObject
  • fgetcsv

也许我在使用$csv_content1 之前不能使用$csv_content2,因为我需要保存某种指针?这种情况下就好了。反正我会按顺序看的。

【问题讨论】:

  • 看来需要增加memory_limit?
  • 解决方案通常是为您的 read_csv_file() 函数编写一些代码来满足您的需求,而不是简单地在 SO 上发布您的要求规范并希望有人会为您做这件事跨度>
  • @Noman 我的文件大小未知。它可以是 10MB 或 1TB。可能不是,但这是我想要计算的范围。
  • @JensTörnell 没错,它不能。该文档没有提到任何关于各种偏移的内容。
  • 没有什么魔法可以从文件中间开始,除非你知道文件中确切的字节位置开始......如果你知道,那么你可以使用@987654328 @;否则你将不得不一次读一行,边走边算,并丢弃你不想得到的行

标签: php csv parsing


【解决方案1】:

经过深思熟虑和阅读,我终于认为我找到了解决问题的方法。如果由于内存使用或从其他角度来看这是一个糟糕的解决方案,请纠正我。

首次运行

$buffer = part($path_to_file, 0, 100);

下一次运行

$buffer = part($path_to_file, $buffer['pointer'], 100);

功能

function part($path, $offset, $rows) {
    $buffer = array();
    $buffer['content'] = '';
    $buffer['pointer'] = array();
    $handle = fopen($path, "r");
    fseek($handle, $offset);
    if( $handle ) {
        for( $i = 0; $i < $rows; $i++ ) {
            $buffer['content'] .= fgets($handle);
            $buffer['pointer'] = mb_strlen($buffer['content']);
        }
    }
    fclose($handle);
    return($buffer);
}

在我更加面向对象的环境中,它看起来更像这样:

function part() {
    $handle = fopen($this->path, "r");
    fseek($handle, $this->pointer);
    if( $handle ) {
        for( $i = 0; $i < 2; $i++ ) {
            if( $this->pointer != $this->filesize ) {
                $this->content .= fgets($handle);
            }
        }
        $this->pointer += mb_strlen($this->content);
    }
    fclose($handle);
}

【讨论】:

  • $this-&gt;pointer += mb_strlen($this-&gt;content); 如果您使用多字节字符集,将会给您带来问题; fseek() 适用于字节,而不适用于字符
  • @MarkBaker 我不这么认为。 mb_strlen 从多字节字符串计算指针。指针本身不是多字节的,它只是一个位置编号。当我使用 strlen 时,它没有找到正确的位置,但是当我使用 mb_strlen 时,它找到了。我已经尝试过 15 次位置跳转,每次都能在我的多字节字符文件中找到正确的位置。
  • @MarkBaker 我尝试将 mb_strlen 更改为“UTF-8”以确保正确获取所有字符,但是当我这样做时它不再起作用。我添加了一个新问题:stackoverflow.com/questions/39724483/…
猜你喜欢
  • 1970-01-01
  • 2020-06-29
  • 1970-01-01
  • 2015-06-02
  • 1970-01-01
  • 2016-12-02
  • 2015-10-10
  • 1970-01-01
  • 2020-11-07
相关资源
最近更新 更多