代码之家  ›  专栏  ›  技术社区  ›  Liren Yeo

无数据库上传、处理和导出csv

  •  0
  • Liren Yeo  · 技术社区  · 6 年前

    我正在建立一个非常简单的网络工具,用户可以上传一个csv文件,然后处理,结果csv可以立即下载。

    上传表单:

    <%= form_tag '/upload', multipart: true do %>
      <%= file_field_tag :csv %>
      <%= submit_tag 'Import CSV' %>
    <% end %>
    

    上载和下载操作:

    def upload
      original_csv = params[:csv]
      p original_csv.path # /var/folders/71/chp2vrc92_19b3jt2fcwhvp80000gn/T/RackMultipart20181025-11469-25guh5.csv
      redirect_to result_path(file_path: original_csv.path)
    end
    
    def result
      p params[:file_path] # /var/folders/71/chp2vrc92_19b3jt2fcwhvp80000gn/T/RackMultipart20181025-11469-25guh5.csv
      output_csv = CSV.generate do |csv|
        CSV.foreach(params[:file_path], headers: true) do |row|
          #############################################
          # "No such file or directory @ rb_sysopen"  #
          # exception is thrown                       #
          #############################################
    
          # each row data is being processed here
          csv << row
        end
      end
    
      # Download the file into user's computer
      send_data output_csv
    end
    

    从注释中可以看到,此方法不起作用,因为临时文件路径不再存在于 result 行动。我怎么能一点也不碰数据库。

    2 回复  |  直到 6 年前
        1
  •  1
  •   spickermann    6 年前

    上载的文件由应用程序存储为临时文件。这意味着一旦请求结束,临时文件将被自动删除。因此,当请求下一页时,它不再存在。

    一种选择是将文件复制到另一个位置,并使其成为文件系统中不再自动删除的“真实”文件。但这也有缺点:现在你也有责任自己管理和删除这些文件。这意味着您需要生成唯一的文件名并将其传递给下一个请求,并且您需要确保文件在下载后被删除,否则这些文件将慢慢消耗服务器磁盘上的所有空间。此外,这不会扩展到多个服务器,只适用于在一个服务器上运行的小型应用程序。

    一个更好的选择可能是只在一个请求中完成上传、处理和下载,而不需要任何重定向。只要能在合理的时间和内存中完成处理,这可能是避免复杂性的好选择。

    def upload
      original_csv = params[:csv]
    
      output_csv = CSV.generate do |csv|
        CSV.foreach(original_csv.path, headers: true) do |row|
          # process data
          csv << row
        end
      end
    
      send_data output_csv
    end
    
        2
  •  0
  •   Masa Sakano    6 年前

    试试这个:

    def upload
      result(params[:csv])
    end
    
    def result(fpath=params[:file_path])
      output_csv = CSV.generate do |csv|
        CSV.foreach(fpath, headers: true) do |row|
          csv << row
        end
      end
    
      # Download the file into user's computer
      send_data output_csv
    end