ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FileSystem.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "FileSystem.h"
9 
10 #include <fcntl.h>
11 
12 #include <algorithm>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <fstream>
16 #include <sstream>
17 
18 #include "CVPlatform.h"
19 #include "Logging.h"
20 #ifdef CV_WINDOWS
21 #include <direct.h>
22 #include <dirent/dirent.h>
23 #include <io.h>
24 #include <windows.h>
25 #ifndef PATH_MAX
26 #define PATH_MAX MAX_PATH
27 #endif
28 #else
29 #include <dirent.h>
30 #include <limits.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 
34 #include <cstring>
35 #endif
36 
37 #ifdef CV_WINDOWS
38 #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
39 #endif
40 #ifdef CV_MAC_OS
41 #include <filesystem>
42 namespace fs = std::__fs::filesystem;
43 #else
44 #include <experimental/filesystem>
45 namespace fs = std::experimental::filesystem;
46 #endif
47 
48 namespace cloudViewer {
49 namespace utility {
50 namespace filesystem {
51 
52 std::string JoinPath(const std::string &path_component1,
53  const std::string &path_component2) {
54  fs::path path(path_component1);
55  return (path / path_component2).string();
56 }
57 
58 std::string JoinPath(const std::vector<std::string> &path_components) {
59  fs::path path;
60  for (const auto &pc : path_components) {
61  path /= pc;
62  }
63  return path.string();
64 }
65 
66 std::string GetEnvVar(const std::string &env_var) {
67  if (const char *env_p = std::getenv(env_var.c_str())) {
68  return {env_p};
69  } else {
70  return "";
71  }
72 }
73 
74 std::string GetHomeDirectory() {
75  std::string home_dir = "";
76 #ifdef CV_WINDOWS
77  // %USERPROFILE%
78  // %HOMEDRIVE%
79  // %HOMEPATH%
80  // %HOME%
81  // C:/
82  home_dir = GetEnvVar("USERPROFILE");
83  if (home_dir.empty() || !DirectoryExists(home_dir)) {
84  home_dir = GetEnvVar("HOMEDRIVE");
85  if (home_dir.empty() || !DirectoryExists(home_dir)) {
86  home_dir = GetEnvVar("HOMEPATH");
87  if (home_dir.empty() || !DirectoryExists(home_dir)) {
88  home_dir = GetEnvVar("HOME");
89  if (home_dir.empty() || !DirectoryExists(home_dir)) {
90  home_dir = "C:/";
91  }
92  }
93  }
94  }
95 #else
96  // $HOME
97  // /
98  home_dir = GetEnvVar("HOME");
99  if (home_dir.empty() || !DirectoryExists(home_dir)) {
100  home_dir = "/";
101  }
102 #endif
103  return home_dir;
104 }
105 
106 std::string EnsureTrailingSlash(const std::string &str) {
107  if (str.length() > 0) {
108  if (str.back() != '/') {
109  return str + "/";
110  }
111  } else {
112  return str + "/";
113  }
114  return str;
115 }
116 
117 bool HasFileExtension(const std::string &file_name, const std::string &ext) {
118  if (ext.empty()) {
119  utility::LogWarning("Given empty extension!");
120  return false;
121  }
122 
123  if (ext.at(0) != '.') {
124  utility::LogWarning("extension should be .xxx, but missing '.'!");
125  return false;
126  }
127 
128  std::string ext_lower = ToLower(ext);
129  if (file_name.size() >= ext_lower.size() &&
130  file_name.substr(file_name.size() - ext_lower.size(),
131  ext_lower.size()) == ext_lower) {
132  return true;
133  }
134  return false;
135 }
136 
137 void SplitFileExtension(const std::string &path,
138  std::string *root,
139  std::string *ext) {
140  auto parts = StringSplit(path, ".", false);
141 
142  if (parts.empty()) {
143  utility::LogError("Empty parts...");
144  }
145  if (parts.size() == 1) {
146  *root = parts[0];
147  *ext = "";
148  } else {
149  *root = "";
150  for (size_t i = 0; i < parts.size() - 1; ++i) {
151  *root += parts[i] + ".";
152  }
153  root->pop_back();
154  // *root = root->substr(0, root->length() - 1);
155  if (parts.back() == "") {
156  *ext = "";
157  } else {
158  *ext = "." + parts.back();
159  }
160  }
161 }
162 
163 bool CopyFile(const std::string &from, const std::string &to) {
164  // Check if source is a directory
165  if (IsDirectory(from)) {
166  utility::LogWarning("Source is a directory, use CopyDir instead: {}",
167  from);
168  return CopyA(from, to);
169  }
170 
171  // Try standard file copy first
172  std::ifstream src(from, std::ios::binary);
173  if (!src) {
174  utility::LogWarning("Source file could not be opened: {}", from);
175  return false;
176  }
177 
178  // Check if destination is a directory
179  if (IsDirectory(to)) {
180  utility::LogWarning("Destination is a directory: {}", to);
181  // Use cross-platform fs::copy
182  return CopyA(from, to);
183  }
184 
185  std::ofstream dst(to, std::ios::binary);
186  if (!dst) {
187  utility::LogError("Target path is not writable: {}", to);
188  return false;
189  }
190 
191  dst << src.rdbuf();
192 
193  if (!dst.good()) {
194  utility::LogError("Error occurred during file copy: {} -> {}", from,
195  to);
196  return false;
197  }
198 
199  return true;
200 }
201 
202 bool CopyDir(const std::string &from, const std::string &to) {
203  DIR *directory = opendir(from.c_str());
204  if (directory == nullptr) {
205  utility::LogError("Cannot open directory: {}", from);
206  return false;
207  }
208 
209  bool ret = true;
210  if (EnsureDirectory(to)) {
211  struct dirent *entry;
212  while ((entry = readdir(directory)) != nullptr) {
213  // skip directory_path/. and directory_path/..
214  if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
215  continue;
216  }
217  const std::string sub_path_from = from + "/" + entry->d_name;
218  const std::string sub_path_to = to + "/" + entry->d_name;
219  if (entry->d_type == DT_DIR) {
220  ret &= CopyDir(sub_path_from, sub_path_to);
221  } else {
222  ret &= CopyFile(sub_path_from, sub_path_to);
223  }
224  }
225  } else {
226  utility::LogError("Cannot create target directory: {}", to);
227  ret = false;
228  }
229  closedir(directory);
230  return ret;
231 }
232 
233 // TODO: this is not a good name. Currently FileSystem.cpp includes windows.h
234 // and "CopyFile" will be expanded to "CopyFileA" on Windows. This will be
235 // resolved when we switch to C++17's std::filesystem.
236 bool CopyA(const std::string &src_path, const std::string &dst_path) {
237  try {
238  fs::copy(src_path, dst_path,
239  fs::copy_options::recursive |
240  fs::copy_options::overwrite_existing);
241  } catch (std::exception &e) {
242  utility::LogWarning("Failed to copy {} to {}. Exception: {}.", src_path,
243  dst_path, e.what());
244  return false;
245  }
246  return true;
247 }
248 
249 bool Copy(const std::string &from,
250  const std::string &to,
251  bool include_parent_dir,
252  const std::string &extname) {
253  if (IsDirectory(from)) {
254  if (extname.empty()) { // ignore extension filter
255  if (include_parent_dir) {
256  return CopyDir(
257  from, JoinPaths(to, GetFileNameWithoutDirectory(from)));
258  } else {
259  return CopyDir(from, to);
260  }
261  } else { // filter files with extname
262  std::vector<std::string> filtered_files;
263  if (!ListFilesInDirectoryWithExtension(from, extname,
264  filtered_files)) {
265  return false;
266  }
267  for (const auto &fn : filtered_files) {
268  if (!CopyFile(fn, to)) {
269  utility::LogWarning("Failed to copy {} to {}", fn.c_str(),
270  to.c_str());
271  return false;
272  }
273  }
274  return true;
275  }
276  } else {
277  return CopyFile(from, to);
278  }
279 }
280 
281 std::string GetFileExtensionInLowerCase(const std::string &filename) {
282  size_t dot_pos = filename.find_last_of(".");
283  if (dot_pos >= filename.length()) return "";
284 
285  if (filename.find_first_of("/\\", dot_pos) != std::string::npos) return "";
286 
287  std::string filename_ext = filename.substr(dot_pos + 1);
288 
289  std::transform(filename_ext.begin(), filename_ext.end(),
290  filename_ext.begin(), ::tolower);
291 
292  return filename_ext;
293 }
294 
295 std::string GetFileNameWithoutExtension(const std::string &filename) {
296  size_t dot_pos = filename.find_last_of(".");
297 
298  return filename.substr(0, dot_pos);
299 }
300 
301 std::string GetFileNameWithoutDirectory(const std::string &filename) {
302  size_t slash_pos = filename.find_last_of("/\\");
303  if (slash_pos == std::string::npos) {
304  return filename;
305  } else {
306  return filename.substr(slash_pos + 1);
307  }
308 }
309 
310 std::string GetFileBaseName(const std::string &filename) {
312 }
313 
314 std::string GetFileParentDirectory(const std::string &filename) {
315  size_t slash_pos = filename.find_last_of("/\\");
316  if (slash_pos == std::string::npos) {
317  return "";
318  } else {
319  return filename.substr(0, slash_pos + 1);
320  }
321 }
322 
323 std::string GetRegularizedDirectoryName(const std::string &directory) {
324  if (directory.empty()) {
325  return "/";
326  } else if (directory.back() != '/' && directory.back() != '\\') {
327  return directory + "/";
328  } else {
329  return directory;
330  }
331 }
332 
333 std::string GetWorkingDirectory() {
334  char buff[PATH_MAX + 1];
335  char *flag = nullptr;
336 #ifdef CV_WINDOWS
337  flag = _getcwd(buff, PATH_MAX + 1);
338 #else
339  flag = getcwd(buff, PATH_MAX + 1);
340 #endif
341  if (flag) {
342  return std::string(buff);
343  } else {
344  return std::string("");
345  }
346 }
347 
348 std::vector<std::string> GetPathComponents(const std::string &path) {
349  auto SplitByPathSeparators = [](const std::string &path) {
350  std::vector<std::string> components;
351  // Split path by '/' and '\'
352  if (!path.empty()) {
353  size_t end = 0;
354  while (end < path.size()) {
355  size_t start = end;
356  while (end < path.size() && path[end] != '\\' &&
357  path[end] != '/') {
358  end++;
359  }
360  if (end > start) {
361  components.push_back(path.substr(start, end - start));
362  }
363  if (end < path.size()) {
364  end++;
365  }
366  }
367  }
368  return components;
369  };
370 
371  auto pathComponents = SplitByPathSeparators(path.c_str());
372 
373  // Handle "/" and "" paths
374  if (pathComponents.empty()) {
375  if (path == "/") {
376  // absolute path; the "/" component will be added
377  // later, so don't do anything here
378  } else {
379  pathComponents.push_back(".");
380  }
381  }
382 
383  char firstChar = path[0]; // '/' doesn't get stored in components
384  bool isRelative = (firstChar != '/');
385  bool isWindowsPath = false;
386  // Check for Windows full path (e.g. "d:")
387  if (isRelative && pathComponents[0].size() >= 2 &&
388  ((firstChar >= 'a' && firstChar <= 'z') ||
389  (firstChar >= 'A' && firstChar <= 'Z')) &&
390  pathComponents[0][1] == ':') {
391  isRelative = false;
392  isWindowsPath = true;
393  }
394 
395  std::vector<std::string> components;
396  if (isRelative) {
398  auto cwdComponents = SplitByPathSeparators(cwd);
399  components.insert(components.end(), cwdComponents.begin(),
400  cwdComponents.end());
401  if (cwd[0] != '/') {
402  isWindowsPath = true;
403  }
404  } else {
405  // absolute path, don't need any prefix
406  }
407  if (!isWindowsPath) {
408  components.insert(components.begin(), "/");
409  }
410 
411  for (auto &dir : pathComponents) {
412  if (dir == ".") { /* ignore */
413  } else if (dir == "..") {
414  components.pop_back();
415  } else {
416  components.push_back(dir);
417  }
418  }
419 
420  return components;
421 }
422 
423 std::string GetTempDirectoryPath() {
424  return fs::temp_directory_path().string();
425 }
426 
427 bool ChangeWorkingDirectory(const std::string &directory) {
428 #ifdef CV_WINDOWS
429  return (_chdir(directory.c_str()) == 0);
430 #else
431  return (chdir(directory.c_str()) == 0);
432 #endif
433 }
434 
435 bool IsFile(const std::string &filename) {
436 #ifdef CV_WINDOWS
437  DWORD attributes = GetFileAttributes(filename.c_str());
438  if (attributes == INVALID_FILE_ATTRIBUTES) return false;
439  return !(attributes & FILE_ATTRIBUTE_DIRECTORY);
440 #else
441  if (0 != access(filename.c_str(), F_OK)) {
442  return false;
443  }
444 
445  struct stat file_stat;
446  if (0 > stat(filename.c_str(), &file_stat)) {
447  perror("get file stat error");
448  return false;
449  }
450  return S_ISREG(file_stat.st_mode);
451 #endif
452 }
453 
454 bool IsDirectory(const std::string &directory) {
455 #ifdef CV_WINDOWS
456  DWORD attributes = GetFileAttributes(directory.c_str());
457  if (attributes == INVALID_FILE_ATTRIBUTES) return false;
458  return (attributes & FILE_ATTRIBUTE_DIRECTORY);
459 #else
460  if (0 != access(directory.c_str(), F_OK)) {
461  return false;
462  }
463 
464  struct stat file_stat;
465  if (0 > stat(directory.c_str(), &file_stat)) {
466  perror("get directory stat error");
467  return false;
468  }
469  return S_ISDIR(file_stat.st_mode);
470 #endif
471 }
472 
473 bool DirectoryExists(const std::string &directory) {
474  return fs::is_directory(directory);
475 }
476 
477 bool DirectoryIsEmpty(const std::string &directory) {
478  if (!DirectoryExists(directory)) {
479  utility::LogError("Directory {} does not exist.", directory);
480  }
481  return fs::is_empty(directory);
482 }
483 
484 bool EnsureDirectory(const std::string &directory_path) {
485  if (!DirectoryExists(directory_path)) {
486  return MakeDirectoryHierarchy(directory_path);
487  }
488  return true;
489 }
490 
491 bool MakeDirectory(const std::string &directory) {
492 #ifdef CV_WINDOWS
493  return (_mkdir(directory.c_str()) == 0);
494 #else
495  return (mkdir(directory.c_str(), S_IRWXU) == 0);
496 #endif
497 }
498 
499 bool MakeDirectoryHierarchy(const std::string &directory) {
500  std::string full_path = GetRegularizedDirectoryName(directory);
501  size_t curr_pos = full_path.find_first_of("/\\", 1);
502  while (curr_pos != std::string::npos) {
503  std::string subdir = full_path.substr(0, curr_pos + 1);
504  if (!DirectoryExists(subdir)) {
505  if (!MakeDirectory(subdir)) {
506  return false;
507  }
508  }
509  curr_pos = full_path.find_first_of("/\\", curr_pos + 1);
510  }
511  return true;
512 }
513 
514 bool DeleteDirectory(const std::string &directory) {
515  std::error_code error;
516  if (fs::remove_all(directory, error) == static_cast<std::uintmax_t>(-1)) {
517  utility::LogWarning("Failed to remove directory {}: {}.", directory,
518  error.message());
519  return false;
520  }
521  return true;
522 }
523 
524 bool FileExists(const std::string &filename) {
525  return fs::exists(filename) && fs::is_regular_file(filename);
526 }
527 
528 bool RemoveFile(const std::string &filename) {
529  return (std::remove(filename.c_str()) == 0);
530 }
531 
532 bool ListDirectory(const std::string &directory,
533  std::vector<std::string> &subdirs,
534  std::vector<std::string> &filenames) {
535  if (directory.empty()) {
536  return false;
537  }
538  DIR *dir;
539  struct dirent *ent;
540  struct stat st;
541  dir = opendir(directory.c_str());
542  if (!dir) {
543  return false;
544  }
545  filenames.clear();
546  while ((ent = readdir(dir)) != NULL) {
547  const std::string file_name = ent->d_name;
548  if (file_name[0] == '.') continue;
549  std::string full_file_name =
550  GetRegularizedDirectoryName(directory) + file_name;
551  if (stat(full_file_name.c_str(), &st) == -1) continue;
552  if (S_ISDIR(st.st_mode))
553  subdirs.push_back(full_file_name);
554  else if (S_ISREG(st.st_mode))
555  filenames.push_back(full_file_name);
556  }
557  closedir(dir);
558  return true;
559 }
560 
561 bool ListFilesInDirectory(const std::string &directory,
562  std::vector<std::string> &filenames) {
563  std::vector<std::string> subdirs;
564  return ListDirectory(directory, subdirs, filenames);
565 }
566 
567 bool ListFilesInDirectoryWithExtension(const std::string &directory,
568  const std::string &extname,
569  std::vector<std::string> &filenames) {
570  std::vector<std::string> all_files;
571  if (!ListFilesInDirectory(directory, all_files)) {
572  return false;
573  }
574  std::string ext_in_lower = extname;
575  std::transform(ext_in_lower.begin(), ext_in_lower.end(),
576  ext_in_lower.begin(), ::tolower);
577  filenames.clear();
578  for (const auto &fn : all_files) {
579  if (GetFileExtensionInLowerCase(fn) == ext_in_lower) {
580  filenames.push_back(fn);
581  }
582  }
583  return true;
584 }
585 
586 std::vector<std::string> FindFilesRecursively(
587  const std::string &directory,
588  std::function<bool(const std::string &)> is_match) {
589  std::vector<std::string> matches;
590 
591  std::vector<std::string> subdirs;
592  std::vector<std::string> files;
593  ListDirectory(directory, subdirs, files); // results are paths
594  for (auto &f : files) {
595  if (is_match(f)) {
596  matches.push_back(f);
597  }
598  }
599  for (auto &d : subdirs) {
600  auto submatches = FindFilesRecursively(d, is_match);
601  if (!submatches.empty()) {
602  matches.insert(matches.end(), submatches.begin(), submatches.end());
603  }
604  }
605 
606  return matches;
607 }
608 
609 FILE *FOpen(const std::string &filename, const std::string &mode) {
610  FILE *fp;
611 #ifndef _WIN32
612  fp = fopen(filename.c_str(), mode.c_str());
613 #else
614  std::wstring filename_w;
615  filename_w.resize(filename.size());
616  int newSize = MultiByteToWideChar(CP_UTF8, 0, filename.c_str(),
617  static_cast<int>(filename.length()),
618  const_cast<wchar_t *>(filename_w.c_str()),
619  static_cast<int>(filename.length()));
620  filename_w.resize(newSize);
621  std::wstring mode_w(mode.begin(), mode.end());
622  fp = _wfopen(filename_w.c_str(), mode_w.c_str());
623 #endif
624  return fp;
625 }
626 
627 std::string GetIOErrorString(const int errnoVal) {
628  switch (errnoVal) {
629  case EPERM:
630  return "Operation not permitted";
631  case EACCES:
632  return "Access denied";
633  // Error below could be EWOULDBLOCK on Linux
634  case EAGAIN:
635  return "Resource unavailable, try again";
636 #if !defined(_WIN32)
637  case EDQUOT:
638  return "Over quota";
639 #endif
640  case EEXIST:
641  return "File already exists";
642  case EFAULT:
643  return "Bad filename pointer";
644  case EINTR:
645  return "open() interrupted by a signal";
646  case EIO:
647  return "I/O error";
648  case ELOOP:
649  return "Too many symlinks, could be a loop";
650  case EMFILE:
651  return "Process is out of file descriptors";
652  case ENAMETOOLONG:
653  return "Filename is too long";
654  case ENFILE:
655  return "File system table is full";
656  case ENOENT:
657  return "No such file or directory";
658  case ENOSPC:
659  return "No space available to create file";
660  case ENOTDIR:
661  return "Bad path";
662  case EOVERFLOW:
663  return "File is too big";
664  case EROFS:
665  return "Can't modify file on read-only filesystem";
666 #if EWOULDBLOCK != EAGAIN
667  case EWOULDBLOCK:
668  return "Operation would block calling process";
669 #endif
670  default: {
671  std::stringstream s;
672  s << "IO error " << errnoVal << " (see sys/errno.h)";
673  return s.str();
674  }
675  }
676 }
677 
678 bool FReadToBuffer(const std::string &path,
679  std::vector<char> &bytes,
680  std::string *errorStr) {
681  bytes.clear();
682  if (errorStr) {
683  errorStr->clear();
684  }
685 
686  FILE *file = FOpen(path.c_str(), "rb");
687  if (!file) {
688  if (errorStr) {
689  *errorStr = GetIOErrorString(errno);
690  }
691 
692  return false;
693  }
694 
695  if (fseek(file, 0, SEEK_END) != 0) {
696  // We ignore that fseek will block our process
697  if (errno && errno != EWOULDBLOCK) {
698  if (errorStr) {
699  *errorStr = GetIOErrorString(errno);
700  }
701 
702  fclose(file);
703  return false;
704  }
705  }
706 
707  const std::size_t filesize = static_cast<std::size_t>(ftell(file));
708  rewind(file); // reset file pointer back to beginning
709 
710  bytes.resize(filesize);
711  const std::size_t result = fread(bytes.data(), 1, filesize, file);
712 
713  if (result != filesize) {
714  if (errorStr) {
715  *errorStr = GetIOErrorString(errno);
716  }
717 
718  fclose(file);
719  return false;
720  }
721 
722  fclose(file);
723  return true;
724 }
725 
726 std::string AddIfExist(const std::string &path,
727  const std::vector<std::string> &folder_names) {
728  for (const auto &folder_name : folder_names) {
729  const std::string folder_path = JoinPath(path, folder_name);
730  if (utility::filesystem::DirectoryExists(folder_path)) {
731  return folder_path;
732  }
733  }
734  return path;
735 }
736 
738 
739 bool CFile::Open(const std::string &filename, const std::string &mode) {
740  Close();
741  file_ = FOpen(filename, mode);
742  if (!file_) {
743  error_code_ = errno;
744  }
745  return bool(file_);
746 }
747 
748 std::string CFile::GetError() { return GetIOErrorString(error_code_); }
749 
750 void CFile::Close() {
751  if (file_) {
752  if (fclose(file_)) {
753  error_code_ = errno;
754  utility::LogError("fclose failed: {}", GetError());
755  }
756  file_ = nullptr;
757  }
758 }
759 
760 int64_t CFile::CurPos() {
761  if (!file_) {
762  utility::LogError("CFile::CurPos() called on a closed file");
763  }
764  int64_t pos = ftell(file_);
765  if (pos < 0) {
766  error_code_ = errno;
767  utility::LogError("ftell failed: {}", GetError());
768  }
769  return pos;
770 }
771 
773  if (!file_) {
774  utility::LogError("CFile::GetFileSize() called on a closed file");
775  }
776  fpos_t prevpos;
777  if (fgetpos(file_, &prevpos)) {
778  error_code_ = errno;
779  utility::LogError("fgetpos failed: {}", GetError());
780  }
781  if (fseek(file_, 0, SEEK_END)) {
782  error_code_ = errno;
783  utility::LogError("fseek failed: {}", GetError());
784  }
785  int64_t size = CurPos();
786  if (fsetpos(file_, &prevpos)) {
787  error_code_ = errno;
788  utility::LogError("fsetpos failed: {}", GetError());
789  }
790  return size;
791 }
792 
794  if (!file_) {
795  utility::LogError("CFile::GetNumLines() called on a closed file");
796  }
797  fpos_t prevpos;
798  if (fgetpos(file_, &prevpos)) {
799  error_code_ = errno;
800  utility::LogError("fgetpos failed: {}", GetError());
801  }
802  if (fseek(file_, 0, SEEK_SET)) {
803  error_code_ = errno;
804  utility::LogError("fseek failed: {}", GetError());
805  }
806  int64_t num_lines = 0;
807  int c;
808  while (EOF != (c = getc(file_))) {
809  if (c == '\n') {
810  num_lines++;
811  }
812  }
813  if (fsetpos(file_, &prevpos)) {
814  error_code_ = errno;
815  utility::LogError("fsetpos failed: {}", GetError());
816  }
817  return num_lines;
818 }
819 
820 const char *CFile::ReadLine() {
821  if (!file_) {
822  utility::LogError("CFile::ReadLine() called on a closed file");
823  }
824  if (line_buffer_.empty()) {
825  line_buffer_.resize(DEFAULT_IO_BUFFER_SIZE);
826  }
827  if (!fgets(line_buffer_.data(), int(line_buffer_.size()), file_)) {
828  if (ferror(file_)) {
829  utility::LogError("CFile::ReadLine() ferror encountered");
830  }
831  if (!feof(file_)) {
833  "CFile::ReadLine() fgets returned NULL, ferror is not set, "
834  "feof is not set");
835  }
836  return nullptr;
837  }
838  if (strlen(line_buffer_.data()) == line_buffer_.size() - 1) {
839  // if we didn't read the whole line, chances are code using this is
840  // not equipped to handle partial line on next call
841  utility::LogError("CFile::ReadLine() encountered a line longer than {}",
842  line_buffer_.size() - 2);
843  }
844  return line_buffer_.data();
845 }
846 
847 size_t CFile::ReadData(void *data, size_t elem_size, size_t num_elems) {
848  if (!file_) {
849  utility::LogError("CFile::ReadData() called on a closed file");
850  }
851  size_t elems = fread(data, elem_size, num_elems, file_);
852  if (ferror(file_)) {
853  utility::LogError("CFile::ReadData() ferror encountered");
854  }
855  if (elems < num_elems) {
856  if (!feof(file_)) {
858  "CFile::ReadData() fread short read, ferror not set, feof "
859  "not set");
860  }
861  }
862  return elems;
863 }
864 
865 } // namespace filesystem
866 } // namespace utility
867 } // namespace cloudViewer
std::string filename
int size
void * bytes
#define NULL
core::Tensor result
Definition: VtkUtils.cpp:76
bool copy
Definition: VtkUtils.cpp:74
std::string GetError()
Returns the last encountered error for this file.
Definition: FileSystem.cpp:748
bool Open(const std::string &filename, const std::string &mode)
Open a file.
Definition: FileSystem.cpp:739
~CFile()
The destructor closes the file automatically.
Definition: FileSystem.cpp:737
int64_t CurPos()
Returns current position in the file (ftell).
Definition: FileSystem.cpp:760
int64_t GetFileSize()
Returns the file size in bytes.
Definition: FileSystem.cpp:772
int64_t GetNumLines()
Returns the number of lines in the file.
Definition: FileSystem.cpp:793
size_t ReadData(T *data, size_t num_elems)
Definition: FileSystem.h:253
#define LogWarning(...)
Definition: Logging.h:72
#define LogError(...)
Definition: Logging.h:60
#define DEFAULT_IO_BUFFER_SIZE
Definition: Logging.h:31
static void error(char *msg)
Definition: lsd.c:159
static const std::string path
Definition: PointCloud.cpp:59
bool ChangeWorkingDirectory(const std::string &directory)
Definition: FileSystem.cpp:427
bool ListFilesInDirectory(const std::string &directory, std::vector< std::string > &filenames)
Definition: FileSystem.cpp:561
bool RemoveFile(const std::string &filename)
Definition: FileSystem.cpp:528
std::vector< std::string > FindFilesRecursively(const std::string &directory, std::function< bool(const std::string &)> is_match)
Definition: FileSystem.cpp:586
bool IsDirectory(const std::string &directory)
Definition: FileSystem.cpp:454
std::string EnsureTrailingSlash(const std::string &str)
Definition: FileSystem.cpp:106
bool DeleteDirectory(const std::string &directory)
Definition: FileSystem.cpp:514
bool Copy(const std::string &from, const std::string &to, bool include_parent_dir=false, const std::string &extname="")
Copy a file or directory.
Definition: FileSystem.cpp:249
bool FReadToBuffer(const std::string &path, std::vector< char > &bytes, std::string *errorStr)
Definition: FileSystem.cpp:678
bool MakeDirectoryHierarchy(const std::string &directory)
Definition: FileSystem.cpp:499
bool CopyFile(const std::string &from, const std::string &to)
Copy a file.
Definition: FileSystem.cpp:163
bool DirectoryIsEmpty(const std::string &directory)
Definition: FileSystem.cpp:477
std::string GetFileParentDirectory(const std::string &filename)
Definition: FileSystem.cpp:314
std::string GetEnvVar(const std::string &env_var)
Definition: FileSystem.cpp:66
bool ListFilesInDirectoryWithExtension(const std::string &directory, const std::string &extname, std::vector< std::string > &filenames)
Definition: FileSystem.cpp:567
void SplitFileExtension(const std::string &path, std::string *root, std::string *ext)
Definition: FileSystem.cpp:137
bool DirectoryExists(const std::string &directory)
Definition: FileSystem.cpp:473
std::string JoinPath(const std::vector< std::string > &path_components)
Definition: FileSystem.cpp:58
std::string GetIOErrorString(const int errnoVal)
Definition: FileSystem.cpp:627
std::string GetFileBaseName(const std::string &filename)
Definition: FileSystem.cpp:310
bool CopyDir(const std::string &from, const std::string &to)
Copy a directory.
Definition: FileSystem.cpp:202
bool EnsureDirectory(const std::string &directory_path)
Check if a specified directory specified by directory_path exists. If not, recursively create the dir...
Definition: FileSystem.cpp:484
std::string GetRegularizedDirectoryName(const std::string &directory)
Definition: FileSystem.cpp:323
std::string GetFileNameWithoutExtension(const std::string &filename)
Definition: FileSystem.cpp:295
std::string GetFileExtensionInLowerCase(const std::string &filename)
Definition: FileSystem.cpp:281
bool FileExists(const std::string &filename)
Definition: FileSystem.cpp:524
bool IsFile(const std::string &filename)
Definition: FileSystem.cpp:435
std::string JoinPaths(T const &...paths)
Definition: FileSystem.h:23
std::vector< std::string > GetPathComponents(const std::string &path)
Definition: FileSystem.cpp:348
bool MakeDirectory(const std::string &directory)
Definition: FileSystem.cpp:491
FILE * FOpen(const std::string &filename, const std::string &mode)
Definition: FileSystem.cpp:609
std::string AddIfExist(const std::string &path, const std::vector< std::string > &folder_names)
Definition: FileSystem.cpp:726
bool HasFileExtension(const std::string &file_name, const std::string &ext)
Definition: FileSystem.cpp:117
std::string GetHomeDirectory()
Get the HOME directory for the user.
Definition: FileSystem.cpp:74
std::string GetFileNameWithoutDirectory(const std::string &filename)
Definition: FileSystem.cpp:301
bool CopyA(const std::string &src_path, const std::string &dst_path)
Definition: FileSystem.cpp:236
bool ListDirectory(const std::string &directory, std::vector< std::string > &subdirs, std::vector< std::string > &filenames)
Definition: FileSystem.cpp:532
std::string ToLower(const std::string &s)
Convert string to the lower case.
Definition: Helper.cpp:242
std::vector< std::string > StringSplit(const std::string &str, const std::string &delimiters=" ", bool trim_empty_str=true)
Definition: Helper.cpp:180
Generic file read and write utility for python interface.
#define SEEK_SET
Definition: qioapi.cpp:38
#define SEEK_END
Definition: qioapi.cpp:34