Apollo 11.0
自动驾驶开放平台
file.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17#include "cyber/common/file.h"
18
19#include <dirent.h>
20#include <fcntl.h>
21#include <glob.h>
22#include <sys/mman.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <unistd.h>
26
27#include <cerrno>
28#include <cstddef>
29#include <fstream>
30#include <string>
31
32#include "google/protobuf/util/json_util.h"
33#include "nlohmann/json.hpp"
34
35namespace apollo {
36namespace cyber {
37namespace common {
38
39using std::istreambuf_iterator;
40using std::string;
41using std::vector;
42
43bool SetProtoToASCIIFile(const google::protobuf::Message &message,
44 int file_descriptor) {
45 using google::protobuf::TextFormat;
46 using google::protobuf::io::FileOutputStream;
47 using google::protobuf::io::ZeroCopyOutputStream;
48 if (file_descriptor < 0) {
49 AERROR << "Invalid file descriptor.";
50 return false;
51 }
52 ZeroCopyOutputStream *output = new FileOutputStream(file_descriptor);
53 bool success = TextFormat::Print(message, output);
54 delete output;
55 close(file_descriptor);
56 return success;
57}
58
59bool SetProtoToASCIIFile(const google::protobuf::Message &message,
60 const std::string &file_name) {
61 int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
62 if (fd < 0) {
63 AERROR << "Unable to open file " << file_name << " to write.";
64 return false;
65 }
66 return SetProtoToASCIIFile(message, fd);
67}
68
69bool SetStringToASCIIFile(const std::string &content,
70 const std::string &file_name) {
71 int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
72 if (fd < 0) {
73 AERROR << "Unable to open file " << file_name << " to write.";
74 return false;
75 }
76 // Write the string data to the file
77 ssize_t bytes_written = write(fd, content.c_str(), content.size());
78 if (bytes_written < 0) {
79 AERROR << "Failed to write to file.";
80 close(fd); // Ensure the file descriptor is closed even on error
81 return false;
82 }
83
84 close(fd); // Close the file descriptor
85
86 return true;
87}
88
89bool GetProtoFromASCIIFile(const std::string &file_name,
90 google::protobuf::Message *message) {
91 using google::protobuf::TextFormat;
92 using google::protobuf::io::FileInputStream;
93 using google::protobuf::io::ZeroCopyInputStream;
94 int file_descriptor = open(file_name.c_str(), O_RDONLY);
95 if (file_descriptor < 0) {
96 AERROR << "Failed to open file " << file_name << " in text mode.";
97 // Failed to open;
98 return false;
99 }
100
101 ZeroCopyInputStream *input = new FileInputStream(file_descriptor);
102 bool success = TextFormat::Parse(input, message);
103 if (!success) {
104 AERROR << "Failed to parse file " << file_name << " as text proto.";
105 }
106 delete input;
107 close(file_descriptor);
108 return success;
109}
110
111bool SetProtoToBinaryFile(const google::protobuf::Message &message,
112 const std::string &file_name) {
113 std::fstream output(file_name,
114 std::ios::out | std::ios::trunc | std::ios::binary);
115 return message.SerializeToOstream(&output);
116}
117
118bool GetProtoFromBinaryFile(const std::string &file_name,
119 google::protobuf::Message *message) {
120 std::fstream input(file_name, std::ios::in | std::ios::binary);
121 if (!input.good()) {
122 AERROR << "Failed to open file " << file_name << " in binary mode.";
123 return false;
124 }
125 if (!message->ParseFromIstream(&input)) {
126 AERROR << "Failed to parse file " << file_name << " as binary proto.";
127 return false;
128 }
129 return true;
130}
131
132bool GetProtoFromFile(const std::string &file_name,
133 google::protobuf::Message *message) {
134 if (!PathExists(file_name)) {
135 AERROR << "File [" << file_name << "] does not exist! ";
136 return false;
137 }
138 // Try the binary parser first if it's much likely a binary proto.
139 static const std::string kBinExt = ".bin";
140 if (std::equal(kBinExt.rbegin(), kBinExt.rend(), file_name.rbegin())) {
141 return GetProtoFromBinaryFile(file_name, message) ||
142 GetProtoFromASCIIFile(file_name, message);
143 }
144
145 return GetProtoFromASCIIFile(file_name, message) ||
146 GetProtoFromBinaryFile(file_name, message);
147}
148
149bool GetProtoFromJsonFile(const std::string &file_name,
150 google::protobuf::Message *message) {
151 using google::protobuf::util::JsonParseOptions;
152 using google::protobuf::util::JsonStringToMessage;
153 std::ifstream ifs(file_name);
154 if (!ifs.is_open()) {
155 AERROR << "Failed to open file " << file_name;
156 return false;
157 }
158 nlohmann::json Json;
159 ifs >> Json;
160 ifs.close();
161 JsonParseOptions options;
162 options.ignore_unknown_fields = true;
163 google::protobuf::util::Status dump_status;
164 return (JsonStringToMessage(Json.dump(), message, options).ok());
165}
166
167bool GetContent(const std::string &file_name, std::string *content) {
168 std::ifstream fin(file_name);
169 if (!fin) {
170 return false;
171 }
172
173 std::stringstream str_stream;
174 str_stream << fin.rdbuf();
175 *content = str_stream.str();
176 return true;
177}
178
179std::string GetAbsolutePath(const std::string &prefix,
180 const std::string &relative_path) {
181 if (relative_path.empty()) {
182 return prefix;
183 }
184 // If prefix is empty or relative_path is already absolute.
185 if (prefix.empty() || relative_path.front() == '/') {
186 return relative_path;
187 }
188
189 if (prefix.back() == '/') {
190 return prefix + relative_path;
191 }
192 return prefix + "/" + relative_path;
193}
194
195bool PathExists(const std::string &path) {
196 struct stat info;
197 return stat(path.c_str(), &info) == 0;
198}
199
200bool PathIsAbsolute(const std::string &path) {
201 if (path.empty()) {
202 return false;
203 }
204 return path.front() == '/';
205}
206
207bool DirectoryExists(const std::string &directory_path) {
208 struct stat info;
209 return stat(directory_path.c_str(), &info) == 0 && (info.st_mode & S_IFDIR);
210}
211
212std::vector<std::string> Glob(const std::string &pattern) {
213 glob_t globs = {};
214 std::vector<std::string> results;
215 if (glob(pattern.c_str(), GLOB_TILDE, nullptr, &globs) == 0) {
216 for (size_t i = 0; i < globs.gl_pathc; ++i) {
217 results.emplace_back(globs.gl_pathv[i]);
218 }
219 }
220 globfree(&globs);
221 return results;
222}
223
224bool CopyFile(const std::string &from, const std::string &to) {
225 std::ifstream src(from, std::ios::binary);
226 if (!src) {
227 AWARN << "Source path could not be normally opened: " << from;
228 std::string command = "cp -r " + from + " " + to;
229 ADEBUG << command;
230 const int ret = std::system(command.c_str());
231 if (ret == 0) {
232 ADEBUG << "Copy success, command returns " << ret;
233 return true;
234 } else {
235 ADEBUG << "Copy error, command returns " << ret;
236 return false;
237 }
238 }
239
240 std::ofstream dst(to, std::ios::binary);
241 if (!dst) {
242 AERROR << "Target path is not writable: " << to;
243 return false;
244 }
245
246 dst << src.rdbuf();
247 return true;
248}
249
250bool CopyDir(const std::string &from, const std::string &to) {
251 DIR *directory = opendir(from.c_str());
252 if (directory == nullptr) {
253 AERROR << "Cannot open directory " << from;
254 return false;
255 }
256
257 bool ret = true;
258 if (EnsureDirectory(to)) {
259 struct dirent *entry;
260 while ((entry = readdir(directory)) != nullptr) {
261 // skip directory_path/. and directory_path/..
262 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
263 continue;
264 }
265 const std::string sub_path_from = from + "/" + entry->d_name;
266 const std::string sub_path_to = to + "/" + entry->d_name;
267 if (entry->d_type == DT_DIR) {
268 ret &= CopyDir(sub_path_from, sub_path_to);
269 } else {
270 ret &= CopyFile(sub_path_from, sub_path_to);
271 }
272 }
273 } else {
274 AERROR << "Cannot create target directory " << to;
275 ret = false;
276 }
277 closedir(directory);
278 return ret;
279}
280
281bool Copy(const std::string &from, const std::string &to) {
282 return DirectoryExists(from) ? CopyDir(from, to) : CopyFile(from, to);
283}
284
285bool EnsureDirectory(const std::string &directory_path) {
286 std::string path = directory_path;
287 for (size_t i = 1; i < directory_path.size(); ++i) {
288 if (directory_path[i] == '/') {
289 // Whenever a '/' is encountered, create a temporary view from
290 // the start of the path to the character right before this.
291 path[i] = 0;
292
293 if (mkdir(path.c_str(), S_IRWXU) != 0) {
294 if (errno != EEXIST) {
295 return false;
296 }
297 }
298
299 // Revert the temporary view back to the original.
300 path[i] = '/';
301 }
302 }
303
304 // Make the final (full) directory.
305 if (mkdir(path.c_str(), S_IRWXU) != 0) {
306 if (errno != EEXIST) {
307 return false;
308 }
309 }
310
311 return true;
312}
313
314bool RemoveAllFiles(const std::string &directory_path) {
315 DIR *directory = opendir(directory_path.c_str());
316 if (directory == nullptr) {
317 AERROR << "Cannot open directory " << directory_path;
318 return false;
319 }
320
321 struct dirent *file;
322 while ((file = readdir(directory)) != nullptr) {
323 // skip directory_path/. and directory_path/..
324 if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
325 continue;
326 }
327 // build the path for each file in the folder
328 std::string file_path = directory_path + "/" + file->d_name;
329 if (unlink(file_path.c_str()) < 0) {
330 AERROR << "Fail to remove file " << file_path << ": " << strerror(errno);
331 closedir(directory);
332 return false;
333 }
334 }
335 closedir(directory);
336 return true;
337}
338
339std::vector<std::string> ListSubPaths(const std::string &directory_path,
340 const unsigned char d_type) {
341 std::vector<std::string> result;
342 DIR *directory = opendir(directory_path.c_str());
343 if (directory == nullptr) {
344 AERROR << "Cannot open directory " << directory_path;
345 return result;
346 }
347
348 struct dirent *entry;
349 while ((entry = readdir(directory)) != nullptr) {
350 // Skip "." and "..".
351 if (entry->d_type == d_type && strcmp(entry->d_name, ".") != 0 &&
352 strcmp(entry->d_name, "..") != 0) {
353 result.emplace_back(entry->d_name);
354 }
355 }
356 closedir(directory);
357 return result;
358}
359
360size_t FindPathByPattern(const std::string &base_path, const std::string &patt,
361 const unsigned char d_type, const bool recursive,
362 std::vector<std::string> *result_list) {
363 DIR *directory = opendir(base_path.c_str());
364 size_t result_cnt = 0;
365 if (directory == nullptr) {
366 AWARN << "cannot open directory " << base_path;
367 return result_cnt;
368 }
369 struct dirent *entry;
370 for (entry = readdir(directory); entry != nullptr;
371 entry = readdir(directory)) {
372 std::string entry_path = base_path + "/" + std::string(entry->d_name);
373 // skip `.` and `..`
374 if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
375 // TODO(liangjinping): support regex or glob or other pattern mode
376 if ((patt == "" || strcmp(entry->d_name, patt.c_str()) == 0) &&
377 entry->d_type == d_type) {
378 // found
379 result_list->emplace_back(entry_path);
380 ++result_cnt;
381 }
382 if (recursive && (entry->d_type == DT_DIR)) {
383 result_cnt +=
384 FindPathByPattern(entry_path, patt, d_type, recursive, result_list);
385 }
386 }
387 }
388 closedir(directory);
389 return result_cnt;
390}
391
392std::string GetDirName(const std::string &path) {
393 std::string::size_type end = path.rfind('/');
394 if (end == std::string::npos) {
395 // not found, return current dir
396 return ".";
397 }
398 return path.substr(0, end);
399}
400
401std::string GetFileName(const std::string &path, const bool remove_extension) {
402 std::string::size_type start = path.rfind('/');
403 if (start == std::string::npos) {
404 start = 0;
405 } else {
406 // Move to the next char after '/'.
407 ++start;
408 }
409
410 std::string::size_type end = std::string::npos;
411 if (remove_extension) {
412 end = path.rfind('.');
413 // The last '.' is found before last '/', ignore.
414 if (end != std::string::npos && end < start) {
415 end = std::string::npos;
416 }
417 }
418 const auto len = (end != std::string::npos) ? end - start : end;
419 return path.substr(start, len);
420}
421
422bool GetFilePathWithEnv(const std::string &path, const std::string &env_var,
423 std::string *file_path) {
424 if (path.empty()) {
425 return false;
426 }
427 if (PathIsAbsolute(path)) {
428 // an absolute path
429 *file_path = path;
430 return PathExists(path);
431 }
432
433 bool relative_path_exists = false;
434 if (PathExists(path)) {
435 // relative path exists
436 *file_path = path;
437 relative_path_exists = true;
438 }
439 if (path.front() == '.') {
440 // relative path but not exist.
441 return relative_path_exists;
442 }
443
444 const char *var = std::getenv(env_var.c_str());
445 if (var == nullptr) {
446 AWARN << "GetFilePathWithEnv: env " << env_var << " not found.";
447 return relative_path_exists;
448 }
449 std::string env_path = std::string(var);
450
451 // search by environment variable
452 size_t begin = 0;
453 size_t index;
454 do {
455 index = env_path.find(':', begin);
456 auto p = env_path.substr(begin, index - begin);
457 if (p.empty()) {
458 continue;
459 }
460 if (p.back() != '/') {
461 p += '/' + path;
462 } else {
463 p += path;
464 }
465 if (PathExists(p)) {
466 *file_path = p;
467 return true;
468 }
469 begin = index + 1;
470 } while (index != std::string::npos);
471 return relative_path_exists;
472}
473
474std::string GetCurrentPath() {
475 char tmp[PATH_MAX];
476 return getcwd(tmp, sizeof(tmp)) ? std::string(tmp) : std::string("");
477}
478
479bool GetType(const string &filename, FileType *type) {
480 struct stat stat_buf;
481 if (lstat(filename.c_str(), &stat_buf) != 0) {
482 return false;
483 }
484 if (S_ISDIR(stat_buf.st_mode) != 0) {
485 *type = TYPE_DIR;
486 } else if (S_ISREG(stat_buf.st_mode) != 0) {
487 *type = TYPE_FILE;
488 } else {
489 AWARN << "failed to get type: " << filename;
490 return false;
491 }
492 return true;
493}
494
495bool DeleteFile(const string &filename) {
496 if (!PathExists(filename)) {
497 return true;
498 }
499 FileType type;
500 if (!GetType(filename, &type)) {
501 return false;
502 }
503 if (type == TYPE_FILE) {
504 if (remove(filename.c_str()) != 0) {
505 AERROR << "failed to remove file: " << filename;
506 return false;
507 }
508 return true;
509 }
510 DIR *dir = opendir(filename.c_str());
511 if (dir == nullptr) {
512 AWARN << "failed to opendir: " << filename;
513 return false;
514 }
515 dirent *dir_info = nullptr;
516 while ((dir_info = readdir(dir)) != nullptr) {
517 if (strcmp(dir_info->d_name, ".") == 0 ||
518 strcmp(dir_info->d_name, "..") == 0) {
519 continue;
520 }
521 string temp_file = filename + "/" + string(dir_info->d_name);
522 FileType temp_type;
523 if (!GetType(temp_file, &temp_type)) {
524 AWARN << "failed to get file type: " << temp_file;
525 closedir(dir);
526 return false;
527 }
528 if (type == TYPE_DIR) {
529 DeleteFile(temp_file);
530 }
531 remove(temp_file.c_str());
532 }
533 closedir(dir);
534 remove(filename.c_str());
535 return true;
536}
537
538bool CreateDir(const string &dir) {
539 int ret = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
540 if (ret != 0) {
541 AWARN << "failed to create dir. [dir: " << dir
542 << "] [err: " << strerror(errno) << "]";
543 return false;
544 }
545 return true;
546}
547
548} // namespace common
549} // namespace cyber
550} // namespace apollo
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AWARN
Definition log.h:43
nlohmann::json Json
bool DeleteFile(const string &filename)
Definition file.cc:495
std::vector< std::string > Glob(const std::string &pattern)
Expand path pattern to matched paths.
Definition file.cc:212
size_t FindPathByPattern(const std::string &base_path, const std::string &patt, const unsigned char d_type, const bool recursive, std::vector< std::string > *result_list)
Find path with pattern
Definition file.cc:360
bool GetProtoFromASCIIFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as ascii representation of protobufs,...
Definition file.cc:89
bool CopyFile(const std::string &from, const std::string &to)
Copy a file.
Definition file.cc:224
bool CreateDir(const string &dir)
Definition file.cc:538
bool GetType(const string &filename, FileType *type)
Definition file.cc:479
bool PathExists(const std::string &path)
Check if the path exists.
Definition file.cc:195
bool GetProtoFromFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as a representation of protobufs,...
Definition file.cc:132
std::string GetDirName(const std::string &path)
get directory name of path
Definition file.cc:392
bool CopyDir(const std::string &from, const std::string &to)
Copy a directory.
Definition file.cc:250
std::string GetCurrentPath()
Definition file.cc:474
bool SetStringToASCIIFile(const std::string &content, const std::string &file_name)
Sets the content of the file specified by the file_name to be the ascii representation of the input s...
Definition file.cc:69
bool GetFilePathWithEnv(const std::string &path, const std::string &env_var, std::string *file_path)
get file path, judgement priority:
Definition file.cc:422
bool Copy(const std::string &from, const std::string &to)
Copy a file or directory.
Definition file.cc:281
bool SetProtoToBinaryFile(const google::protobuf::Message &message, const std::string &file_name)
Sets the content of the file specified by the file_name to be the binary representation of the input ...
Definition file.cc:111
std::string GetFileName(const std::string &path, const bool remove_extension)
Definition file.cc:401
bool GetProtoFromJsonFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the json file specified by the file_name as ascii representation of protobufs,...
Definition file.cc:149
bool SetProtoToASCIIFile(const google::protobuf::Message &message, int file_descriptor)
Definition file.cc:43
std::string GetAbsolutePath(const std::string &prefix, const std::string &relative_path)
Get absolute path by concatenating prefix and relative_path.
Definition file.cc:179
bool RemoveAllFiles(const std::string &directory_path)
Remove all the files under a specified directory.
Definition file.cc:314
bool PathIsAbsolute(const std::string &path)
Definition file.cc:200
bool DirectoryExists(const std::string &directory_path)
Check if the directory specified by directory_path exists and is indeed a directory.
Definition file.cc:207
bool GetProtoFromBinaryFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as binary representation of protobufs,...
Definition file.cc:118
bool GetContent(const std::string &file_name, std::string *content)
Get file content as string.
Definition file.cc:167
std::vector< std::string > ListSubPaths(const std::string &directory_path, const unsigned char d_type)
List sub-paths.
Definition file.cc:339
bool EnsureDirectory(const std::string &directory_path)
Check if a specified directory specified by directory_path exists.
Definition file.cc:285
class register implement
Definition arena_queue.h:37