SigUtil  0.95
Utility modules for modern C++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
file_tmp(save,read num).hpp
Go to the documentation of this file.
1 /*
2 Copyright(c) 2014 Akihiro Nishimura
3 
4 This software is released under the MIT License.
5 http://opensource.org/licenses/mit-license.php
6 */
7 
8 #ifndef SIG_UTIL_FILE_HPP
9 #define SIG_UTIL_FILE_HPP
10 
11 #include "string.hpp"
12 #include "helper/helper.hpp"
13 
14 #include <fstream>
15 #include <locale>
16 
17 #if SIG_MSVC_ENV
18  #include <windows.h>
19 #elif SIG_USE_BOOST_FILESYSTEM
20  #include <boost/filesystem.hpp>
21  namespace fs = boost::filesystem;
22 #endif
23 
24 
25 /* 入出力関連 */
26 
27 namespace sig
28 {
29 
30 // ディレクトリ・ファイルパスの末尾に'/'or'\'があるかチェックし、付けるか外すかどうか指定
31 inline auto modify_dirpass_tail(FilepassString const& directory_pass, bool const has_slash) ->FilepassString
32 {
33  if (directory_pass.empty()) return directory_pass;
34 
35  auto tail = directory_pass.back();
36 
37  if (has_slash){
38  //付ける場合
39  if (tail == '/' || tail == '\\') return directory_pass;
40 #if SIG_MSVC_ENV
41  else return (directory_pass + L"/");
42 #else
43  else return (directory_pass + "/");
44 #endif
45  }
46  else{
47  if (tail != '/' && tail != '\\') return directory_pass;
48  else{
49  auto tmp = directory_pass;
50  tmp.pop_back();
51  return tmp;
52  }
53  }
54 };
55 
56 // 指定ディレクトリにあるファイル名を取得
57 // 必要条件:VisualStudio環境 または boostのインクルード
58 // directry_pass:調べたいディレクトリのパス
59 // hidden_file:true->隠しファイルのみ, false->非隠しファイルのみ (Windows, Linux環境のみ)
60 // extension:拡張子指定(オプション)
61 // 読み込み失敗: return -> nothing or empty-vector
62 inline auto get_file_names(
63  FilepassString const& directory_pass,
64  bool hidden_file,
65  std::wstring extension = L""
66  ) ->Just<std::vector<std::wstring>>
67 {
68  typedef std::vector<std::wstring> ResultType;
69  ResultType result;
70 
71 #if SIG_MSVC_ENV
72  WIN32_FIND_DATA fd;
73  auto query = extension.empty() ? L"?*" : L"*" + extension;
74  auto pass = modify_dirpass_tail(directory_pass, true) + query;
75  auto hFind = FindFirstFile(pass.c_str(), &fd);
76 
77  if (hFind == INVALID_HANDLE_VALUE){
78  return Nothing(std::move(result));
79  }
80  else{
81  do{
82  if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && Consistency(hidden_file, (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)))
83  {
84  result.push_back(std::wstring(fd.cFileName));
85  }
86  } while (FindNextFile(hFind, &fd));
87 
88  FindClose(hFind);
89  return Just<ResultType>(std::move(result));
90  }
91 #elif SIG_ENABLE_BOOST
92  auto IsHidden = [](fs::path const& p){
93  auto name = p.filename();
94  if (name.c_str()[0] == '.' && name != ".." && name != ".") return true;
95  else return false;
96  };
97 
98  fs::directory_iterator end;
99  for (fs::directory_iterator it(directory_pass); it != end; ++it)
100  {
101  if (!fs::is_directory(*it) && Consistency(hidden_file, IsHidden(*it))){
102  auto leaf = sig::split(it->path().wstring(), L"/").back();
103  if (extension.empty()) result.push_back(leaf);
104  else{
105  auto query = L".*(" + escape_regex(extension) + L")";
106  auto ext = sig::regex_search(leaf, SIG_WRegex(query));
107  if (is_container_valid(ext) && fromJust(ext)[0][1] == extension) result.push_back(leaf);
108  }
109  }
110  }
111  return Just<ResultType>::type(std::move(result));
112 #else
113  std::cout << "I don't support this envirnment which is default. please include boost if any." << std::endl;
114  assert(false);
115 #endif
116 }
117 
118 // 指定ディレクトリにあるフォルダ名を取得
119 // 必要条件:VisualStudio環境 または boostのインクルード
120 // directry_pass:調べたいディレクトリのパス
121 // hidden_file:true->隠しファイルのみ, false->非隠しファイルのみ (Windows, Linux環境のみ)
122 // 読み込み失敗: return -> nothing or empty-vector
123 inline auto get_folder_names(
124  FilepassString const& directory_pass,
125  bool hidden_file
126  ) ->Just<std::vector<std::wstring>>
127 {
128  typedef std::vector<std::wstring> ResultType;
129  ResultType result;
130 
131 #if SIG_MSVC_ENV
132  WIN32_FIND_DATA fd;
133  auto pass = modify_dirpass_tail(directory_pass, true) + L"*";
134  auto hFind = FindFirstFile(pass.c_str(), &fd);
135 
136  if (hFind == INVALID_HANDLE_VALUE){
137  return Nothing(std::move(result));
138  }
139  else{
140  do{
141  if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && Consistency(hidden_file, (fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)))
142  {
143  auto tmp = std::wstring(fd.cFileName);
144  if(tmp != L"." && tmp != L"..") result.push_back(tmp);
145  }
146  } while (FindNextFile(hFind, &fd));
147 
148  FindClose(hFind);
149  return Just<ResultType>(std::move(result));
150  }
151 #elif SIG_ENABLE_BOOST
152  auto IsHidden = [](fs::path const& p){
153  auto name = p.filename();
154  if (name.c_str()[0] == '.' && name != ".." && name != ".") return true;
155  else return false;
156  };
157 
158  fs::directory_iterator end;
159  for (fs::directory_iterator it(directory_pass); it != end; ++it)
160  {
161  if (fs::is_directory(*it) && Consistency(hidden_file, IsHidden(*it))){
162  result.push_back(sig::split(it->path().wstring(), L"/").back());
163  }
164  }
165  return Just<ResultType>(std::move(result));
166 #else
167  std::cout << "I don't support this envirnment which is default. please include boost if any." << std::endl;
168  assert(false);
169 #endif
170 }
171 
172 
173 //overwrite:上書き, append:末尾追記
174 enum class WriteMode{ overwrite, append };
175 
176 //ファイル内容の初期化
177 // file_pass: 保存先のディレクトリとファイル名(フルパス)
178 inline void clear_file(FilepassString const& file_pass)
179 {
180  std::ofstream ofs(file_pass);
181  ofs << "";
182 }
183 
184 #define SIG_FILE_LOCALE_INIT\
185  static bool first = true;\
186  if (first){\
187  std::locale::global(std::locale(""));\
188  first = false;\
189  }
190 
191 /* Save Text */
192 
193 // ファイルへ1行ずつ保存
194 // src: 保存対象
195 // ofs: std::ofstream or std::wofstream
196 template <class T, typename std::enable_if<!container_traits<T>::exist>::type*& = enabler>
197 inline void save_line(
198  T src,
199  typename impl::FStreamSelector<T>::ofstream& ofs)
200 {
201  ofs << src << std::endl;
202 }
203 
204 // ファイルへ1行ずつ保存
205 // src: 保存対象(コンテナ)
206 // ofs: std::ofstream or std::wofstream
207 template <class C, typename std::enable_if<container_traits<C>::exist>::type*& = enabler>
209  C const& src,
210  typename impl::FStreamSelector<typename container_traits<C>::value_type>::ofstream& ofs)
211 {
212  typename impl::FStreamSelector<typename container_traits<C>::value_type>::ostreambuf_iterator streambuf_iter(ofs);
213  for (auto const& str : src){
214  std::copy(str.begin(), str.end(), streambuf_iter);
215  streambuf_iter = '\n';
216  }
217 }
218 
219 // ファイルへ1行ずつ保存
220 // src: 保存対象
221 // file_pass: 保存先のディレクトリとファイル名(フルパス)
222 // open_mode: 上書き(overwrite) or 追記(append)
223 template <class T, typename std::enable_if<!container_traits<T>::exist>::type*& = enabler>
224 void save_line(
225  T src,
226  FilepassString const& file_pass,
228 {
230 
231  const auto open_mode = mode == WriteMode::overwrite ? std::ios::out : std::ios::out | std::ios::app;
232  typename impl::FStreamSelector<T>::ofstream ofs(file_pass, open_mode);
233  save_line(src, ofs);
234 }
235 
236 // ファイルへ1行ずつ保存
237 // src: 保存対象(コンテナ)
238 // file_pass: 保存先のディレクトリとファイル名(フルパス)
239 // open_mode: 上書き(overwrite) or 追記(append)
240 template <class C, typename std::enable_if<container_traits<C>::exist>::type*& = enabler>
241 void save_line(
242  C const& src,
243  FilepassString const& file_pass,
245 {
247 
248  const auto open_mode = mode == WriteMode::overwrite ? std::ios::out : std::ios::out | std::ios::app;
249  typename impl::FStreamSelector<typename container_traits<C>::value_type>::ofstream ofs(file_pass, open_mode);
250  save_line(src, ofs);
251 }
252 
253 
254 // 数値列(ex:ベクトル)の保存
255 // src: 保存対象(コンテナ)
256 // file_pass: 保存先のディレクトリとファイル名(フルパス)
257 // open_mode: 上書き(overwrite) or 追記(append)
258 // delimiter: 数値間の区切り文字を指定(デフォルトは\n)
259 template <class C, typename std::enable_if<container_traits<C>::exist && !container_traits<typename container_traits<C>::value_type>::exist>::type*& = enabler>
260 void save_num(
261  C const& src,
262  FilepassString const& file_pass,
264  std::string delimiter = "\n")
265 {
266  save_line(cat_str(src, delimiter), file_pass, mode);
267 }
268 
269 // 2次元配列の数値(ex:行列)を保存
270 // src: 保存対象(コンテナのコンテナ)
271 // file_pass: 保存先のディレクトリとファイル名(フルパス)
272 // open_mode: 上書き(overwrite) or 追記(append)
273 // delimiter1: 数値間の区切り文字を指定(デフォルトは\n)
274 // delimiter2: 行間の区切り文字指定(デフォルトは\n\n)
275 template <class CC, typename std::enable_if<container_traits<typename container_traits<CC>::value_type>::exist>::type*& = enabler>
276 void save_num(
277  CC const& src,
278  FilepassString const& file_pass,
280  std::string delimiter1 = "\n",
281  std::string delimiter2 = "\n\n")
282 {
283  std::vector<std::string> tmp;
284 
285  for (auto const& line : src){
286  tmp.push_back(cat_str(line, delimiter1));
287  }
288  save_line(tmp, file_pass, mode);
289 }
290 
291 
292 /* Read Text */
293 
294 template <class R>
296 
297 // ファイルから1行ずつ読み込む
298 // empty_dest: 保存先の空のコンテナ
299 // ifs: std::ifstream or std::wifstream
300 // conv: 読み込んだ文字列から任意型Rへの変換関数(文字列 -> 数値型へはread_numを推奨) string or wstring -> R
301 template <class C, class R = typename container_traits<C>::value_type>
303  C& empty_dest,
304  IfsSelector<R>& ifs,
305  std::function< R(typename impl::SameIf<R, std::string, std::string, std::wstring>::type) > const& conv = nullptr)
306 {
307  static_assert(std::is_same<R, typename container_traits<C>::value_type>::value, "error in read_line: R and C::value_type don't match");
308 
310 
312 
313  while (ifs && std::getline(ifs, line)){
314  conv ? container_traits<C>::add_element(empty_dest, conv(std::move(line))) : container_traits<C>::add_element(empty_dest, std::move(line));
315  }
316  return static_cast<bool>(ifs);
317 }
318 
319 // ファイルから1行ずつ読み込む
320 // empty_dest: 保存先の空のコンテナ
321 // file_pass: 読み込み先のディレクトリとファイル名(フルパス)
322 // conv: 読み込んだ文字列から任意型Rへの変換関数(文字列 -> 数値型へはread_numを推奨) string or wstring -> R
323 template <class C, class R = typename container_traits<C>::value_type>
325  C& empty_dest,
326  FilepassString const& file_pass,
327  std::function< R(typename impl::SameIf<R, std::string, std::string, std::wstring>::type)> const& conv = nullptr)
328 {
329  IfsSelector<R> ifs(file_pass);
330  if (!ifs){
331  //FileOpenErrorPrint(file_pass);
332  return false;
333  }
334  return read_line(empty_dest, ifs, conv);
335 }
336 
337 // ファイルから1行ずつ読み込み、結果を返す
338 // R: 返す文字列型(std::string or std::wstring)
339 // ifs: std::ifstream or std::wifstream
340 // 読込失敗: return -> nothing (boost非使用時は空のコンテナ)
341 template <class R, class C = std::vector<R>>
342 auto read_line(IfsSelector<R>& ifs) ->Just<C>
343 {
344  C tmp;
345  read_line(tmp, ifs);
346  return tmp.size() ? Just<C>(std::move(tmp)) : Nothing(std::move(tmp));
347 }
348 
349 // ファイルから1行ずつ読み込み、結果を返す
350 // R: 返す文字列型(std::string or std::wstring)
351 // file_pass: 読み込み先のディレクトリとファイル名(フルパス)
352 // 読込失敗: return -> nothing (boost非使用時は空のコンテナ)
353 template <class R, class C = std::vector<R>>
354 auto read_line(FilepassString const& file_pass) ->Just<C>
355 {
356  IfsSelector<R> ifs(file_pass);
357  if (!ifs){
358  //FileOpenErrorPrint(file_pass);
359  return Nothing(C());
360  }
361  return read_line<R, C>(ifs);
362 }
363 
364 template <class R, class C = std::vector<R>>
365 auto read_line(FilepassStringC file_pass) ->Just<C>
366 {
367  return read_line<R, C>(static_cast<impl::TString<FilepassStringC>>(file_pass));
368 }
369 
370 
371 // 数値列を読み込む
372 // empty_dest: 保存先の空のコンテナ
373 // file_pass: 読み込み先のディレクトリとファイル名(フルパス)
374 // delimiter: 数値間の区切り文字を指定 (デフォルトは\n)
375 // return -> 読み込みの成否
376 template <class C, class RT = typename container_traits<C>::value_type, typename std::enable_if<!container_traits<typename container_traits<C>::value_type>::exist>::type*& = enabler>
377 bool read_num(
378  C& empty_dest,
379  FilepassString const& file_pass,
380  std::string delimiter = "\n")
381 {
382  auto read_str = read_line<std::string>(file_pass);
383 
384  if (!is_container_valid(read_str)) return false;
385 
386  if (delimiter == "\n"){
387  for (auto const& line : fromJust(read_str)){
388  container_traits<C>::add_element(empty_dest, impl::Str2NumSelector<RT>()(line));
389  }
390  }
391  else{
392  // 遅いので注意
393  auto sp = split(fromJust(read_str)[0], delimiter);
394  for (auto v : sp) container_traits<C>::add_element(empty_dest, impl::Str2NumSelector<RT>()(v));
395  }
396  return true;
397 }
398 
399 // 2次元配列の数値(ex:行列)を読み込む
400 // empty_dest: 保存先の空のコンテナのコンテナ
401 // file_pass: 読み込み先のディレクトリとファイル名(フルパス)
402 // delimiter1: 数値間の区切り文字を指定(デフォルトは\n)
403 // delimiter2: 行間の区切り文字指定(デフォルトは\n\n)
404 // return -> 読み込みの成否
405 template <class CC, class RC = typename container_traits<CC>::value_type, class RT = typename container_traits<RC>::value_type>
406 bool read_num(
407  CC& empty_dest,
408  FilepassString const& file_pass,
409  std::string delimiter1 = "\n",
410  std::string delimiter2 = "\n\n")
411 {
412  auto read_str = read_line<std::string>(file_pass);
413  if (!is_container_valid(read_str)) return false;
414 
415  for (auto const& line : fromJust(read_str)){
416  RC tmp;
417  auto sp = split(line, delimiter);
418 
419  for (auto const& v : sp){
420  container_traits<RC>::add_element(tmp, impl::Str2NumSelector<RT>()(v));
421  }
422  container_traits<CC>::add_element(empty_dest, std::move(tmp));
423  }
424  return true;
425 }
426 
427 // 数値列を読み込み、結果のコンテナを返す
428 // file_pass: 読み込み先のディレクトリとファイル名(フルパス)
429 // delimiter: 数値間の区切り文字を指定 (デフォルトは行区切り)
430 // 読込失敗: return -> nothing (boost非使用時は空のコンテナ)
431 template <class C, typename std::enable_if<container_traits<C>::exist && !container_traits<typename container_traits<C>::value_type>::exist>::type*& = enabler>
432 auto read_num(
433  FilepassString const& file_pass,
434  std::string delimiter = "\n"
435  ) ->Just<C>
436 {
437  C tmp;
438  read_num(tmp, file_pass, delimiter);
439  return tmp.size() ? Just<C>(std::move(tmp)) : Nothing(std::move(tmp));
440 }
441 
442 // 2次元配列の数値(ex:行列)を読み込む
443 // file_pass: 読み込み先のディレクトリとファイル名(フルパス)
444 // delimiter: 数値間の区切り文字を指定
445 // 読込失敗: return -> nothing (boost非使用時は空のコンテナ)
446 template <class CC, typename std::enable_if<container_traits<typename container_traits<CC>::value_type>::exist>::type*& = enabler>
447 auto read_num(
448  FilepassString const& file_pass,
449  std::string delimiter
450  ) ->Just<CC>
451 {
452  CC tmp;
453  read_num(tmp, file_pass, delimiter);
454  return tmp.size() ? Just<CC>(std::move(tmp)) : Nothing(std::move(tmp));
455 }
456 
457  /*
458  //csvで保存
459  template <class Num>
460  void SaveCSV(std::vector<std::vector<Num>> const& data, std::vector<std::string> const& row_names, std::vector<std::string> const& col_names, std::wstring const& out_fullpass)
461  {
462  std::ofstream ofs(out_fullpass);
463 
464  //first row: field name
465  ofs << ",";
466  for (uint i = 1; i < data[0].size() + 1; ++i){
467  auto name = i - 1 < col_names.size() ? col_names[i - 1] : "";
468  ofs << i << ". " << name << ",";
469  }
470  ofs << "\n";
471 
472  //first col: field name
473  for (uint j = 0; j < data.size(); ++j){
474  auto name = j < row_names.size() ? row_names[j] : "";
475  ofs << j + 1 << ". " << name << ",";
476 
477  for (auto e : data[j]){
478  ofs << e << ",";
479  }
480  ofs << "\n";
481  }
482  }
483  */
484 }
485 
486 #endif
bool read_num(C &empty_dest, FilepassString const &file_pass, std::string delimiter="\n")
typename impl::SameIf< R, std::string, std::ifstream, std::wifstream >::type IfsSelector
std::wregex SIG_WRegex
Definition: regex.hpp:32
bool read_line(C &empty_dest, IfsSelector< R > &ifs, std::function< R(typename impl::SameIf< R, std::string, std::string, std::wstring >::type) > const &conv=nullptr)
auto get_folder_names(FilepassString const &directory_pass, bool hidden_file) -> Maybe< std::vector< std::wstring >>
指定ディレクトリにあるフォルダ名を取得
Definition: pass.hpp:143
void clear_file(FilepassString const &file_pass)
ファイル内容の初期化
Definition: save.hpp:43
auto split(S const &src, impl::string_t< S > const &delimiter) -> CSeq< TS >
文字列(src)をある文字列(delimiter)を目印に分割する
Definition: manipulate.hpp:40
auto end(C &&c) -> std::move_iterator< typename RC::iterator >
void * enabler
auto Nothing() -> typename impl::SameIf< T, void, typename boost::none_t, Maybe< T >>::type
値コンストラクタ
Definition: maybe.hpp:67
WriteMode
SaveLine, SaveNum の保存に関する設定
Definition: save.hpp:24
auto modify_dirpass_tail(FilepassString const &directory_pass, bool const has_slash) -> FilepassString
ディレクトリ・ファイルパスの末尾に'/'or'\'があるかチェックし、付けるか外すかどうかを指定して反映 ...
Definition: pass.hpp:43
auto get_file_names(FilepassString const &directory_pass, bool hidden_file, std::wstring extension=L"") -> Maybe< std::vector< std::wstring >>
指定ディレクトリにあるファイル名を取得
Definition: pass.hpp:75
void save_num(C const &src, FilepassString const &file_pass, std::string delimiter, WriteMode open_mode=WriteMode::overwrite)
数値列(ex:ベクトル)の保存
Definition: save.hpp:202
bool Consistency(B1 &&a, B2 &&b)
AとBの真偽一致でtrueを返す (⇔ !xor)
void save_line(T src, typename impl::FStreamSelector< T >::ofstream &ofs)
ファイルへ1行ずつ保存
Definition: save.hpp:59
typename std::conditional< std::is_same< T1, T2 >::value, TrueT, FalseT >::type type
T & fromJust(Maybe< T > &m)
Justから値を取り出す関数.Maybe a -> a.
Definition: maybe.hpp:113
auto regex_search(S &&src, typename impl::Str2RegexSelector< TS >::regex const &expression) -> Maybe< std::vector< std::vector< TS >>>
std::regex_search のラッパ関数
Definition: regex.hpp:172
#define SIG_FILE_LOCALE_INIT
auto escape_regex(std::string const &expression) -> std::string
与えられた文字中に含まれる、正規表現の特殊文字をエスケープする
Definition: regex.hpp:88
Definition: array.hpp:15
auto copy(C &&src) -> RC
別の種類のコンテナに要素をコピーする