[Elixir006]CSV(Comma-separated values)處理

1. CSV文件格式是什麼

CSV有時也稱爲字符分隔值,因爲分隔字符也可以不是逗號),其文件以純文本形式存儲表格數據(數字和文本)。純文本意味着該文件是一個字符序列,不含必須像二進制數字那樣被解讀的數據。CSV文件由任意數目的記錄組成,記錄間以某種換行符分隔;每條記錄由字段組成,字段間的分隔符是其它字符或字符串,最常見的是逗號或製表符。通常,所有記錄都有完全相同的字段序列。

Elixir有好幾個CSV處理的庫(cessocsvcsvlixirex_csv), beatrichartz/cvs寫得特別好,用了stream, test coverage(100%),而且有benchmark.

mix new csv_play
cd csv_play
emacs mix.exs
defp deps do
    [{:csv, "~> 1.2.0"},
     {:faker, "~>0.5.1"}
    ]
end

2. Faker測試數據

faker用來假造一些測試數據,接下來我們搞一個腳本生成csv數據

mix deps.get
mkdir scripts
emacs scripts/generate_csv_data.exs
Faker.start
count = 10_000
headers = ~w(name company city)

data =  1..count
|> Enum.map(fn(_) ->
  [Faker.Name.first_name <> Faker.Name.last_name, Faker.Company.name, Faker.Address.city]
end)

file = File.open!("sample_data.csv", [:write])

[headers | data]
|> CSV.encode
|> Enum.each(&IO.write(file, &1))

:ok = File.close(file)
mix run scripts/generate_csv_data.exs

3.CSV decode示例

我們來測試一下csv的header讀得是否正確

mkdir test/data/
mv sample_data.csv test/data/
emacs test/csv_play_test.exs
defmodule CsvPlayTest do
  use ExUnit.Case
  @data_path "test/data/sample_data.csv"

  test "reading CSV as a list" do
    list =
    @data_path
    |> File.stream!
    |> CSV.decode
    |> Enum.to_list
    assert hd(list) == ["name", "company", "city"]
  end
end

通常我們的cvs數據量都是非常大的,所以我們使用stream一塊一塊的來處理成map。

test "reading CSV as a map" do
    list = @data_path
    |> File.stream!
    |> CSV.decode(headers: true)
    |> Enum.to_list

    sorted_keys = list
    |> hd
    |> Map.keys
    |> Enum.sort

    assert sorted_keys == Enum.sort(["name", "company", "city"])
  end

當然你CSV decode時還可以指定分割符是什麼(默認就是上面這種形式的逗號)

CSV.decode(separator: ?\t)

Resources

 1. beatrichartz/csv

 2. igas/faker


How I felt when I understood Elixir error messages for the first time

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章