Here's a way with expl3 and Heiko Oberdiek's catchfile:
\documentclass{article}
\usepackage[T1]{fontenc} % for the underscore
\usepackage{catchfile}
\usepackage{xparse}
\ExplSyntaxOn
\cs_set_eq:NN \egreg_catchfiledef:nnn \CatchFileDef
\cs_generate_variant:Nn \egreg_catchfiledef:nnn { c }
\cs_generate_variant:Nn \seq_set_split:Nnn { Nnv }
\NewDocumentCommand{\storefile}{ m m } % #1 = symbolic name, #2 = file name
{
\egreg_catchfiledef:cnn { l_egreg_ #1 _list_tl } { #2 } { \char_set_catcode_other:N \_ }
}
\NewDocumentCommand{\printtable}{ m m } % #1 = number of columns, #2 = symbolic name
{
\egreg_printtable:nn { #1 } { #2 }
}
\tl_new:N \l_egreg_temp_table_tl
\seq_new:N \l_egreg_temp_list_seq
\int_new:N \l_egreg_col_count_int
\cs_new_protected:Npn \egreg_printtable:nn #1 #2
{
\seq_set_split:Nnv \l_egreg_temp_list_seq { , } { l_egreg_ #2 _list_tl }
\tl_clear:N \l_egreg_temp_table_tl
\int_zero:N \l_egreg_col_count_int
\seq_map_inline:Nn \l_egreg_temp_list_seq
{
\int_incr:N \l_egreg_col_count_int
\tl_put_right:Nn \l_egreg_temp_table_tl { ##1 }
\int_compare:nTF { \l_egreg_col_count_int = #1 }
{ \tl_put_right:Nn \l_egreg_temp_table_tl { \\ } \int_zero:N \l_egreg_col_count_int }
{ \tl_put_right:Nn \l_egreg_temp_table_tl { & } }
}
\begin{tabular}{*{#1}{c}}
\l_egreg_temp_table_tl
\end{tabular}
}
\ExplSyntaxOff
\begin{document}
\storefile{words}{my_words.txt}
\noindent Three words per line
\noindent\printtable{3}{words}
\bigskip
\noindent Five words per line
\noindent\printtable{5}{words}
\bigskip
\noindent Eight words per line
\noindent\printtable{8}{words}
\end{document}
The \storefile stores the contents of the file under a symbolic name (in this case words). Then \printtable can print the table using the data.

We first define an expl3 equivalent to \CatchFileDef for being able to generate variants for it. Then the \storefile command is defined: it takes a symbolic name for the word list and the file name as arguments. It stores the entire file in a token list variable (underscores will be absorbed as printable characters).
The \printtable gets the desired number of columns and the symbolic name of the list as arguments. It's, as usual, simply translated into a function call.
The function splits the token list corresponding to the symbolic name at commas and does a mapping on the sequence thus obtained. At each step we increment a counter and add the word to a temporary token list; if the counter's value is not the number of columns we add also a &, otherwise we add \\ and reset the counter to zero.
Finally, the entire list is printed inside a tabular. You might want to load longtable and change tabular into longtable if the word list is long.
For choosing between "row" and "column" order, you can modify it like this:
\documentclass{article}
\usepackage[T1]{fontenc} % for the underscore
\usepackage{catchfile,multicol}
\usepackage{xparse}
\ExplSyntaxOn
\cs_set_eq:NN \egreg_catchfiledef:nnn \CatchFileDef
\cs_generate_variant:Nn \egreg_catchfiledef:nnn { c }
\cs_generate_variant:Nn \seq_set_split:Nnn { Nnv }
\NewDocumentCommand{\storefile}{ m m } % #1 = symbolic name, #2 = file name
{
\egreg_catchfiledef:cnn { l_egreg_ #1 _list_tl } { #2 } { \char_set_catcode_other:N \_ }
}
\NewDocumentCommand{\printtable}{ s m m } % #2 = number of columns, #3 = symbolic name
{
\IfBooleanTF{#1}
{ \egreg_printtablev:nn { #2 } { #3 } }
{ \egreg_printtable:nn { #2 } { #3 } }
}
\tl_new:N \l_egreg_temp_table_tl
\seq_new:N \l_egreg_temp_list_seq
\int_new:N \l_egreg_col_count_int
\cs_new_protected:Npn \egreg_printtable:nn #1 #2
{
\seq_set_split:Nnv \l_egreg_temp_list_seq { , } { l_egreg_ #2 _list_tl }
\tl_clear:N \l_egreg_temp_table_tl
\int_zero:N \l_egreg_col_count_int
\seq_map_inline:Nn \l_egreg_temp_list_seq
{
\int_incr:N \l_egreg_col_count_int
\tl_put_right:Nn \l_egreg_temp_table_tl { ##1 }
\int_compare:nTF { \l_egreg_col_count_int = #1 }
{ \tl_put_right:Nn \l_egreg_temp_table_tl { \\ } \int_zero:N \l_egreg_col_count_int }
{ \tl_put_right:Nn \l_egreg_temp_table_tl { & } }
}
\begin{tabular}{*{#1}{c}}
\l_egreg_temp_table_tl
\end{tabular}
}
\cs_new_protected:Npn \egreg_printtablev:nn #1 #2
{
\seq_set_split:Nnv \l_egreg_temp_list_seq { , } { l_egreg_ #2 _list_tl }
\begin{multicols}{3}\centering
\seq_map_inline:Nn \l_egreg_temp_list_seq { ##1 \par }
\end{multicols}
}
\ExplSyntaxOff
\begin{document}
\storefile{words}{my_words.txt}
\noindent Three words per line
\noindent\printtable{3}{words}
\bigskip
\noindent Five words per line
\noindent\printtable{5}{words}
\bigskip
\noindent Three equispaced columns (column order)
\noindent\printtable*{14}{words}
\end{document}