【问题标题】:How to parse Large CSV file without timing out?如何在不超时的情况下解析大型 CSV 文件?
【发布时间】:2012-08-01 18:15:23
【问题描述】:

我正在尝试解析一个 50 兆字节的 .csv 文件。该文件本身很好,但我试图解决所涉及的大量超时问题。每个都设置为上传明智,我可以轻松上传并重新打开文件,但在浏览器超时后,我收到 500 内部错误。

我的猜测是我可以将文件保存到服务器上,打开它并保留我处理的行的会话值。在某一行之后,我通过刷新重置连接并在我离开的那一行打开文件。这是一个可行的想法吗?之前的开发者做了一个效率非常低的 MySQL 类,它控制着整个站点,所以我不想写自己的类,如果我不需要,我也不想乱他的类。

TL;DR 版本: 保存我当前在具有 38K 行产品的 CSV 文件的最后一行然后在 X 行后重置连接是否有效从我离开的地方开始?还是有另一种方法来解析大型 CSV 文件而不会超时?

注意:这是 PHP 脚本的执行时间。目前在 38K 行,通过命令行运行大约需要 46 分 5 秒。当我从浏览器中删除它时,它 100% 正常工作,这表明它是浏览器超时。据 Google 告诉我,Chrome 的超时是不可编辑的,而 Firefox 的超时很少起作用。

【问题讨论】:

  • 您应该详细说明什么是超时。您与 MySQL 的连接、PHP 脚本执行时间还是其他什么?您是否考虑过将超时设置更长的时间?
  • 您应该首先考虑让脚本拆分文件。
  • @JYelton I 这是 PHP 脚本的执行时间。目前在 38K 行,通过命令行运行大约需要 46 分 5 秒。当我从浏览器中删除它时,它 100% 正常工作,这表明它是浏览器超时。据谷歌告诉我,Chrome 的超时是不可编辑的,而 Firefox 的超时很少起作用。
  • 46 分钟完成
  • 查看旧开发人员的代码,我注意到他们使用了大约 15 个 if...else 语句、7 个函数(每个函数至少有 10 个 if...else 语句),并且每个函数执行一些非常低效的 MySQL 查询。我完全同意该接口是为 KB 数据设计的,但不幸的是,我有一个时间紧迫的问题,即“快速或肮脏,我们不在乎。在你今天离开之前找到修复程序。”所以我想我会试一试我的想法,然后我会回复结果。感谢大家的想法。

标签: php mysql csv timeout


【解决方案1】:

你可以这样做:

<?php

namespace database;

class importcsv
{
    private $crud;

    public function __construct($dbh, $table)
    {
        $this->crud = new \database\crud($dbh, $table);
        return $this;
    }

    public function import($columnNames, $csv, $seperator)
    {
        $lines = explode("\n", $csv);

        foreach($lines as $line)
        {
            \set_time_limit(30);
            $line = explode($seperator, $line);

            $data = new \stdClass();

            foreach($line as $i => $item) 
            {
                if(isset($columnNames[$i])&&!empty($columnNames[$i]))
                    $data->$columnNames[$i] = $item;
            }

            @$x++;

            $this->crud->create($data);
        }

        return $x;
    }

    public function importFile($columnNames, $csvPath, $seperator)
    {
        if(file_exists($csvPath))
        {
            $content = file_get_contents($csvPath);
            return $this->import($columnNames, $content, $seperator);
        }
        else
        {
            // Error
        }
    }
}

TL;DR:\set_time_limit(30); 每次循环一行时可能会解决您的超时问题。

【讨论】:

  • 这是一段不错的代码,如果不是因为我的产品有很多不同的事情需要发生而不是仅仅进行插入,它就会起作用。谢谢,我可能会将代码用于其他想法。
  • 不知道 set_timeout 会重置时间。你刚刚为我节省了很多小时的工作! :)
【解决方案2】:

我建议从命令行运行 php 并将其设置为 cron 作业。这样您就不必修改代码。不会有超时问题,您可以轻松解析大型 CSV 文件。

也可以查看link

【讨论】:

  • 我希望我可以执行此选项,但它必须在页面上运行,并且必须由完全不知道网站如何运作的人来完成。我不能给他们命令行访问权限并要求他们每周运行一次,因为他们会告诉我不,并在他们的拒绝中添加一些其他丰富多彩的词。
  • 我把我接受的答案改成了这个。这正是我所做的。我将包发送到服务器并将其作为 cron 作业运行。运行平稳,经过 12 小时的会话。那个 50MB 的文件变成了 256MB 的文件,每次解析需要 1 小时。感谢您的帮助。
【解决方案3】:

由于拼写错误和语法,您的帖子有点不清楚,请您编辑一下吗?

如果你说 Upload 本身没问题,但延迟是在处理文件,那么最简单的做法是使用多个线程并行解析文件。您可以使用 java 内置的 Executor 类,或者 Quartz 或 Jetlang 来执行此操作。

  • 查找文件大小或行数。
  • 选择线程加载(假设每个线程 1000 行)
  • 启动执行器
  • 循环读取文件。
  • 对于每 1000 行,创建一个 Runnable 并将其加载到 Executor 中
  • 启动执行器
  • 等到所有线程都完成

每个可运行对象都这样做:

  1. 获取连接
  2. 插入 1000 行
  3. 记录结果
  4. 关闭连接

【讨论】:

    猜你喜欢
    • 2012-04-28
    • 2018-12-22
    • 1970-01-01
    • 2014-02-06
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    相关资源
    最近更新 更多