Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

receiving :badarg on File.write

Tags:

elixir

I am starting to learn Elixir, and this is also my first dynamic language, so I am really lost working with functions without type declaration.

What I am trying to do:
def create_training_data(file_path, indices_path, result_path) do
    file_path
    |> File.stream!
    |> Stream.with_index
    |> filter_data_with_indices(indices_path)
    |> create_output_file(result_path)
  end

  def filter_data_with_indices(raw_data, indices_path) do
    Stream.filter raw_data, fn {_elem, index} ->
      index_match?(index, indices_path)
    end
  end

  defp index_match?(index, indices_path) do
    indices_path
    |> File.stream!
    |> Enum.any? fn elem ->
      (elem
      |> String.replace(~r/\n/, "")
      |> String.to_integer
      |> (&(&1 == index)).())
    end
  end

  defp create_output_file(data, path) do
    File.write(path, data)
  end

When I call the function:

create_training_data("./resources/data/usps.csv","./resources/indices/17.csv","./output.txt")

It returns {:error, :badarg}. I already checked and the error is on the create_output_file function.

If I comment out the function create_output_file, what I get back is a stream (kinda makes sense). Would the problem be maybe that I cannot give a Stream to File.write? If it is a problem, what should I do? I did not find anything regarding that on the documentation.

Edit

So, the thing is that the path to File.write should be ok, I modified the function to be like this:

defp create_output_file(data, path) do
    IO.puts("You are trying to write to: " <> path)
    File.write(path, data)
end

Now again when I try to run with these parameters:

iex(3)> IaBay.DataHandling.create_training_data("/home/lhahn/data/usps.csv", "/home/lhahn/indices/17.csv", "/home/lhahn/output.txt")
You are trying to write to: /home/lhahn/output.txt
{:error, :badarg}
iex(4)> File.write("/home/lhahn/output.txt", "Hello, World")
:ok

So, I still got the :badarg problem, maybe the content that I am passing is not right?

like image 977
lhahn Avatar asked May 14 '15 00:05

lhahn


2 Answers

First thing: you feed tuples into write. You must first extract data from them:

file_path
|> File.stream!
|> Stream.with_index
|> filter_data_with_indices(indices_path)
|> Stream.map(fn {x,y} -> x end)    # <------------------ here
|> create_output_file(result_path)

Second thing:

It looks like you can't feed Stream into File.write/2 because it expects iodata. If you convert stream into list before writing, everything goes well:

defp create_output_file(data, path) do
  data = Enum.to_list(data)
  :ok = File.write(path, data)
end
like image 131
Miroslav Prymek Avatar answered Sep 29 '22 15:09

Miroslav Prymek


Does the directory you are writing to exists? I would try this:

defp create_output_file(data, path) do
  File.mkdir_p!(Path.dirname(path))
  File.write!(path, data)
end
like image 33
José Valim Avatar answered Sep 29 '22 13:09

José Valim