Apollo 10.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 IsValidPath(const std::string &path) {
251 const std::string illegal_chars = "\0<>:\"|?*;";
252 for (char ch : path) {
253 if (illegal_chars.find(ch) != std::string::npos) {
254 return false;
255 }
256 }
257 return true;
258}
259
260bool CopyDir(const std::string &from, const std::string &to) {
261 DIR *directory = opendir(from.c_str());
262 if (directory == nullptr) {
263 AERROR << "Cannot open directory " << from;
264 return false;
265 }
266 if (!IsValidPath(from) || !IsValidPath(to)) {
267 AERROR << "invalid path format: " << from << " to " << to;
268 return false;
269 }
270
271 bool ret = true;
272 if (EnsureDirectory(to)) {
273 struct dirent *entry;
274 while ((entry = readdir(directory)) != nullptr) {
275 // skip directory_path/. and directory_path/..
276 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
277 continue;
278 }
279 const std::string sub_path_from = from + "/" + entry->d_name;
280 const std::string sub_path_to = to + "/" + entry->d_name;
281 if (entry->d_type == DT_DIR) {
282 ret &= CopyDir(sub_path_from, sub_path_to);
283 } else {
284 ret &= CopyFile(sub_path_from, sub_path_to);
285 }
286 }
287 } else {
288 AERROR << "Cannot create target directory " << to;
289 ret = false;
290 }
291 closedir(directory);
292 return ret;
293}
294
295bool Copy(const std::string &from, const std::string &to) {
296 return DirectoryExists(from) ? CopyDir(from, to) : CopyFile(from, to);
297}
298
299bool EnsureDirectory(const std::string &directory_path) {
300 std::string path = directory_path;
301 for (size_t i = 1; i < directory_path.size(); ++i) {
302 if (directory_path[i] == '/') {
303 // Whenever a '/' is encountered, create a temporary view from
304 // the start of the path to the character right before this.
305 path[i] = 0;
306
307 if (mkdir(path.c_str(), S_IRWXU) != 0) {
308 if (errno != EEXIST) {
309 return false;
310 }
311 }
312
313 // Revert the temporary view back to the original.
314 path[i] = '/';
315 }
316 }
317
318 // Make the final (full) directory.
319 if (mkdir(path.c_str(), S_IRWXU) != 0) {
320 if (errno != EEXIST) {
321 return false;
322 }
323 }
324
325 return true;
326}
327
328bool RemoveAllFiles(const std::string &directory_path) {
329 DIR *directory = opendir(directory_path.c_str());
330 if (directory == nullptr) {
331 AERROR << "Cannot open directory " << directory_path;
332 return false;
333 }
334
335 struct dirent *file;
336 while ((file = readdir(directory)) != nullptr) {
337 // skip directory_path/. and directory_path/..
338 if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) {
339 continue;
340 }
341 // build the path for each file in the folder
342 std::string file_path = directory_path + "/" + file->d_name;
343 if (unlink(file_path.c_str()) < 0) {
344 AERROR << "Fail to remove file " << file_path << ": " << strerror(errno);
345 closedir(directory);
346 return false;
347 }
348 }
349 closedir(directory);
350 return true;
351}
352
353std::vector<std::string> ListSubPaths(const std::string &directory_path,
354 const unsigned char d_type) {
355 std::vector<std::string> result;
356 DIR *directory = opendir(directory_path.c_str());
357 if (directory == nullptr) {
358 AERROR << "Cannot open directory " << directory_path;
359 return result;
360 }
361
362 struct dirent *entry;
363 while ((entry = readdir(directory)) != nullptr) {
364 // Skip "." and "..".
365 if (entry->d_type == d_type && strcmp(entry->d_name, ".") != 0 &&
366 strcmp(entry->d_name, "..") != 0) {
367 result.emplace_back(entry->d_name);
368 }
369 }
370 closedir(directory);
371 return result;
372}
373
374size_t FindPathByPattern(const std::string &base_path, const std::string &patt,
375 const unsigned char d_type, const bool recursive,
376 std::vector<std::string> *result_list) {
377 DIR *directory = opendir(base_path.c_str());
378 size_t result_cnt = 0;
379 if (directory == nullptr) {
380 AWARN << "cannot open directory " << base_path;
381 return result_cnt;
382 }
383 struct dirent *entry;
384 for (entry = readdir(directory); entry != nullptr;
385 entry = readdir(directory)) {
386 std::string entry_path = base_path + "/" + std::string(entry->d_name);
387 // skip `.` and `..`
388 if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
389 // TODO(liangjinping): support regex or glob or other pattern mode
390 if ((patt == "" || strcmp(entry->d_name, patt.c_str()) == 0) &&
391 entry->d_type == d_type) {
392 // found
393 result_list->emplace_back(entry_path);
394 ++result_cnt;
395 }
396 if (recursive && (entry->d_type == DT_DIR)) {
397 result_cnt +=
398 FindPathByPattern(entry_path, patt, d_type, recursive, result_list);
399 }
400 }
401 }
402 closedir(directory);
403 return result_cnt;
404}
405
406std::string GetDirName(const std::string &path) {
407 std::string::size_type end = path.rfind('/');
408 if (end == std::string::npos) {
409 // not found, return current dir
410 return ".";
411 }
412 return path.substr(0, end);
413}
414
415std::string GetFileName(const std::string &path, const bool remove_extension) {
416 std::string::size_type start = path.rfind('/');
417 if (start == std::string::npos) {
418 start = 0;
419 } else {
420 // Move to the next char after '/'.
421 ++start;
422 }
423
424 std::string::size_type end = std::string::npos;
425 if (remove_extension) {
426 end = path.rfind('.');
427 // The last '.' is found before last '/', ignore.
428 if (end != std::string::npos && end < start) {
429 end = std::string::npos;
430 }
431 }
432 const auto len = (end != std::string::npos) ? end - start : end;
433 return path.substr(start, len);
434}
435
436bool GetFilePathWithEnv(const std::string &path, const std::string &env_var,
437 std::string *file_path) {
438 if (path.empty()) {
439 return false;
440 }
441 if (PathIsAbsolute(path)) {
442 // an absolute path
443 *file_path = path;
444 return PathExists(path);
445 }
446
447 bool relative_path_exists = false;
448 if (PathExists(path)) {
449 // relative path exists
450 *file_path = path;
451 relative_path_exists = true;
452 }
453 if (path.front() == '.') {
454 // relative path but not exist.
455 return relative_path_exists;
456 }
457
458 const char *var = std::getenv(env_var.c_str());
459 if (var == nullptr) {
460 AWARN << "GetFilePathWithEnv: env " << env_var << " not found.";
461 return relative_path_exists;
462 }
463 std::string env_path = std::string(var);
464
465 // search by environment variable
466 size_t begin = 0;
467 size_t index;
468 do {
469 index = env_path.find(':', begin);
470 auto p = env_path.substr(begin, index - begin);
471 if (p.empty()) {
472 continue;
473 }
474 if (p.back() != '/') {
475 p += '/' + path;
476 } else {
477 p += path;
478 }
479 if (PathExists(p)) {
480 *file_path = p;
481 return true;
482 }
483 begin = index + 1;
484 } while (index != std::string::npos);
485 return relative_path_exists;
486}
487
488std::string GetCurrentPath() {
489 char tmp[PATH_MAX];
490 return getcwd(tmp, sizeof(tmp)) ? std::string(tmp) : std::string("");
491}
492
493bool GetType(const string &filename, FileType *type) {
494 struct stat stat_buf;
495 if (lstat(filename.c_str(), &stat_buf) != 0) {
496 return false;
497 }
498 if (S_ISDIR(stat_buf.st_mode) != 0) {
499 *type = TYPE_DIR;
500 } else if (S_ISREG(stat_buf.st_mode) != 0) {
501 *type = TYPE_FILE;
502 } else {
503 AWARN << "failed to get type: " << filename;
504 return false;
505 }
506 return true;
507}
508
509bool DeleteFile(const string &filename) {
510 if (!PathExists(filename)) {
511 return true;
512 }
513 FileType type;
514 if (!GetType(filename, &type)) {
515 return false;
516 }
517 if (type == TYPE_FILE) {
518 if (remove(filename.c_str()) != 0) {
519 AERROR << "failed to remove file: " << filename;
520 return false;
521 }
522 return true;
523 }
524 DIR *dir = opendir(filename.c_str());
525 if (dir == nullptr) {
526 AWARN << "failed to opendir: " << filename;
527 return false;
528 }
529 dirent *dir_info = nullptr;
530 while ((dir_info = readdir(dir)) != nullptr) {
531 if (strcmp(dir_info->d_name, ".") == 0 ||
532 strcmp(dir_info->d_name, "..") == 0) {
533 continue;
534 }
535 string temp_file = filename + "/" + string(dir_info->d_name);
536 FileType temp_type;
537 if (!GetType(temp_file, &temp_type)) {
538 AWARN << "failed to get file type: " << temp_file;
539 closedir(dir);
540 return false;
541 }
542 if (type == TYPE_DIR) {
543 DeleteFile(temp_file);
544 }
545 remove(temp_file.c_str());
546 }
547 closedir(dir);
548 remove(filename.c_str());
549 return true;
550}
551
552bool CreateDir(const string &dir) {
553 int ret = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
554 if (ret != 0) {
555 AWARN << "failed to create dir. [dir: " << dir
556 << "] [err: " << strerror(errno) << "]";
557 return false;
558 }
559 return true;
560}
561
562} // namespace common
563} // namespace cyber
564} // 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:509
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:374
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:552
bool GetType(const string &filename, FileType *type)
Definition file.cc:493
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:406
bool CopyDir(const std::string &from, const std::string &to)
Copy a directory.
Definition file.cc:260
std::string GetCurrentPath()
Definition file.cc:488
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:436
bool Copy(const std::string &from, const std::string &to)
Copy a file or directory.
Definition file.cc:295
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:415
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:328
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:353
bool EnsureDirectory(const std::string &directory_path)
Check if a specified directory specified by directory_path exists.
Definition file.cc:299
bool IsValidPath(const std::string &path)
Definition file.cc:250
class register implement
Definition arena_queue.h:37