OR-Tools  8.2
file.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 
17 #include "absl/strings/str_cat.h"
18 #if defined(_MSC_VER)
19 #include <io.h>
20 #define access _access
21 #define F_OK 0
22 #else
23 #include <unistd.h>
24 #endif
25 
26 #include <cstring>
27 #include <memory>
28 #include <string>
29 
30 #include "ortools/base/file.h"
31 #include "ortools/base/logging.h"
32 
33 File::File(FILE* const f_des, const absl::string_view& name)
34  : f_(f_des), name_(name) {}
35 
36 bool File::Delete(const char* const name) { return remove(name) == 0; }
37 
38 bool File::Exists(const char* const name) { return access(name, F_OK) == 0; }
39 
40 size_t File::Size() {
41  struct stat f_stat;
42  stat(name_.data(), &f_stat);
43  return f_stat.st_size;
44 }
45 
46 bool File::Flush() { return fflush(f_) == 0; }
47 
48 bool File::Close() {
49  if (fclose(f_) == 0) {
50  f_ = NULL;
51  return true;
52  } else {
53  return false;
54  }
55 }
56 
57 absl::Status File::Close(int flags) {
58  if (flags != file::Defaults())
59  return absl::Status(absl::StatusCode::kInvalidArgument, "Wrong flags");
60  return Close()
61  ? absl::OkStatus()
62  : absl::Status(absl::StatusCode::kInvalidArgument,
63  absl::StrCat("Could not close file '", name_, "'"));
64 }
65 
66 void File::ReadOrDie(void* const buf, size_t size) {
67  CHECK_EQ(fread(buf, 1, size, f_), size);
68 }
69 
70 size_t File::Read(void* const buf, size_t size) {
71  return fread(buf, 1, size, f_);
72 }
73 
74 void File::WriteOrDie(const void* const buf, size_t size) {
75  CHECK_EQ(fwrite(buf, 1, size, f_), size);
76 }
77 size_t File::Write(const void* const buf, size_t size) {
78  return fwrite(buf, 1, size, f_);
79 }
80 
81 File* File::OpenOrDie(const char* const name, const char* const flag) {
82  FILE* const f_des = fopen(name, flag);
83  if (f_des == NULL) {
84  std::cerr << "Cannot open " << name;
85  exit(1);
86  }
87  File* const f = new File(f_des, name);
88  return f;
89 }
90 
91 File* File::Open(const char* const name, const char* const flag) {
92  FILE* const f_des = fopen(name, flag);
93  if (f_des == NULL) return NULL;
94  File* const f = new File(f_des, name);
95  return f;
96 }
97 
98 char* File::ReadLine(char* const output, uint64 max_length) {
99  return fgets(output, max_length, f_);
100 }
101 
102 int64 File::ReadToString(std::string* const output, uint64 max_length) {
103  CHECK(output != nullptr);
104  output->clear();
105 
106  if (max_length == 0) return 0;
107 
108  int64 needed = max_length;
109  int bufsize = (needed < (2 << 20) ? needed : (2 << 20));
110 
111  std::unique_ptr<char[]> buf(new char[bufsize]);
112 
113  int64 nread = 0;
114  while (needed > 0) {
115  nread = Read(buf.get(), (bufsize < needed ? bufsize : needed));
116  if (nread > 0) {
117  output->append(buf.get(), nread);
118  needed -= nread;
119  } else {
120  break;
121  }
122  }
123  return (nread >= 0 ? static_cast<int64>(output->size()) : -1);
124 }
125 
126 size_t File::WriteString(const std::string& line) {
127  return Write(line.c_str(), line.size());
128 }
129 
130 bool File::WriteLine(const std::string& line) {
131  if (Write(line.c_str(), line.size()) != line.size()) return false;
132  return Write("\n", 1) == 1;
133 }
134 
135 absl::string_view File::filename() const { return name_; }
136 
137 bool File::Open() const { return f_ != NULL; }
138 
139 void File::Init() {}
140 
141 namespace file {
142 absl::Status Open(const absl::string_view& filename,
143  const absl::string_view& mode, File** f, int flags) {
144  if (flags == Defaults()) {
145  *f = File::Open(filename, mode.data());
146  if (*f != nullptr) {
147  return absl::OkStatus();
148  }
149  }
150  return absl::Status(absl::StatusCode::kInvalidArgument,
151  absl::StrCat("Could not open '", filename, "'"));
152 }
153 
154 File* OpenOrDie(const absl::string_view& filename,
155  const absl::string_view& mode, int flags) {
156  File* f;
157  CHECK_EQ(flags, Defaults());
158  f = File::Open(filename, mode.data());
159  CHECK(f != nullptr) << absl::StrCat("Could not open '", filename, "'");
160  return f;
161 }
162 
163 absl::Status GetContents(const absl::string_view& filename, std::string* output,
164  int flags) {
165  if (flags == Defaults()) {
166  File* file = File::Open(filename, "r");
167  if (file != NULL) {
168  const int64 size = file->Size();
169  if (file->ReadToString(output, size) == size) return absl::OkStatus();
170 #if defined(_MSC_VER)
171  // On windows, binary files needs to be opened with the "rb" flags.
172  file->Close();
173  // Retry in binary mode.
174  File* file = File::Open(filename, "rb");
175  const int64 b_size = file->Size();
176  if (file->ReadToString(output, b_size) == b_size) return absl::OkStatus();
177 #endif // _MSC_VER
178  }
179  }
180  return absl::Status(absl::StatusCode::kInvalidArgument,
181  absl::StrCat("Could not read '", filename, "'"));
182 }
183 
184 absl::Status WriteString(File* file, const absl::string_view& contents,
185  int flags) {
186  if (flags == Defaults() && file != NULL &&
187  file->Write(contents.data(), contents.size()) == contents.size() &&
188  file->Close()) {
189  return absl::OkStatus();
190  }
191  return absl::Status(
192  absl::StatusCode::kInvalidArgument,
193  absl::StrCat("Could not write ", contents.size(), " bytes"));
194 }
195 
196 absl::Status SetContents(const absl::string_view& filename,
197  const absl::string_view& contents, int flags) {
198  return WriteString(File::Open(filename, "w"), contents, flags);
199 }
200 
201 bool ReadFileToString(const absl::string_view& file_name, std::string* output) {
202  return GetContents(file_name, output, file::Defaults()).ok();
203 }
204 
205 bool WriteStringToFile(const std::string& data,
206  const absl::string_view& file_name) {
207  return SetContents(file_name, data, file::Defaults()).ok();
208 }
209 
210 namespace {
211 class NoOpErrorCollector : public google::protobuf::io::ErrorCollector {
212  public:
213  virtual void AddError(int line, int column, const std::string& message) {}
214 };
215 } // namespace
216 
217 bool ReadFileToProto(const absl::string_view& file_name,
218  google::protobuf::Message* proto) {
219  std::string str;
220  if (!ReadFileToString(file_name, &str)) {
221  LOG(INFO) << "Could not read " << file_name;
222  return false;
223  }
224  // Attempt to decode ASCII before deciding binary. Do it in this order because
225  // it is much harder for a binary encoding to happen to be a valid ASCII
226  // encoding than the other way around. For instance "index: 1\n" is a valid
227  // (but nonsensical) binary encoding. We want to avoid printing errors for
228  // valid binary encodings if the ASCII parsing fails, and so specify a no-op
229  // error collector.
230  NoOpErrorCollector error_collector;
231  google::protobuf::TextFormat::Parser parser;
232  parser.RecordErrorsTo(&error_collector);
233  if (parser.ParseFromString(str, proto)) {
234  return true;
235  }
236  if (proto->ParseFromString(str)) {
237  return true;
238  }
239  // Re-parse the ASCII, just to show the diagnostics (we could also get them
240  // out of the ErrorCollector but this way is easier).
241  google::protobuf::TextFormat::ParseFromString(str, proto);
242  LOG(INFO) << "Could not parse contents of " << file_name;
243  return false;
244 }
245 
246 void ReadFileToProtoOrDie(const absl::string_view& file_name,
247  google::protobuf::Message* proto) {
248  CHECK(ReadFileToProto(file_name, proto)) << "file_name: " << file_name;
249 }
250 
251 bool WriteProtoToASCIIFile(const google::protobuf::Message& proto,
252  const absl::string_view& file_name) {
253  std::string proto_string;
254  return google::protobuf::TextFormat::PrintToString(proto, &proto_string) &&
255  WriteStringToFile(proto_string, file_name);
256 }
257 
258 void WriteProtoToASCIIFileOrDie(const google::protobuf::Message& proto,
259  const absl::string_view& file_name) {
260  CHECK(WriteProtoToASCIIFile(proto, file_name)) << "file_name: " << file_name;
261 }
262 
263 bool WriteProtoToFile(const google::protobuf::Message& proto,
264  const absl::string_view& file_name) {
265  std::string proto_string;
266  return proto.AppendToString(&proto_string) &&
267  WriteStringToFile(proto_string, file_name);
268 }
269 
270 void WriteProtoToFileOrDie(const google::protobuf::Message& proto,
271  const absl::string_view& file_name) {
272  CHECK(WriteProtoToFile(proto, file_name)) << "file_name: " << file_name;
273 }
274 
275 absl::Status GetTextProto(const absl::string_view& filename,
276  google::protobuf::Message* proto, int flags) {
277  if (flags == Defaults()) {
278  if (ReadFileToProto(filename, proto)) return absl::OkStatus();
279  }
280  return absl::Status(
281  absl::StatusCode::kInvalidArgument,
282  absl::StrCat("Could not read proto from '", filename, "'."));
283 }
284 
285 absl::Status SetTextProto(const absl::string_view& filename,
286  const google::protobuf::Message& proto, int flags) {
287  if (flags == Defaults()) {
288  if (WriteProtoToASCIIFile(proto, filename)) return absl::OkStatus();
289  }
290  return absl::Status(
291  absl::StatusCode::kInvalidArgument,
292  absl::StrCat("Could not write proto to '", filename, "'."));
293 }
294 
295 absl::Status SetBinaryProto(const absl::string_view& filename,
296  const google::protobuf::Message& proto, int flags) {
297  if (flags == Defaults()) {
298  if (WriteProtoToFile(proto, filename)) return absl::OkStatus();
299  }
300  return absl::Status(
301  absl::StatusCode::kInvalidArgument,
302  absl::StrCat("Could not write proto to '", filename, "'."));
303 }
304 
305 absl::Status Delete(const absl::string_view& path, int flags) {
306  if (flags == Defaults()) {
307  if (remove(path.data()) == 0) return absl::OkStatus();
308  }
309  return absl::Status(absl::StatusCode::kInvalidArgument,
310  absl::StrCat("Could not delete '", path, "'."));
311 }
312 
313 absl::Status Exists(const absl::string_view& path, int flags) {
314  if (flags == Defaults()) {
315  if (access(path.data(), F_OK) == 0) return absl::OkStatus();
316  }
317  return absl::Status(absl::StatusCode::kInvalidArgument,
318  absl::StrCat("File '", path, "' does not exist."));
319 }
320 } // namespace file
#define CHECK(condition)
Definition: base/logging.h:495
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:697
#define LOG(severity)
Definition: base/logging.h:420
Definition: base/file.h:32
bool Open() const
Definition: file.cc:137
static File * OpenOrDie(const char *const name, const char *const flag)
Definition: file.cc:81
static void Init()
Definition: file.cc:139
static bool Exists(const char *const name)
Definition: file.cc:38
void WriteOrDie(const void *const buff, size_t size)
Definition: file.cc:74
bool Flush()
Definition: file.cc:46
void ReadOrDie(void *const buff, size_t size)
Definition: file.cc:66
size_t Write(const void *const buff, size_t size)
Definition: file.cc:77
char * ReadLine(char *const output, uint64 max_length)
Definition: file.cc:98
size_t Size()
Definition: file.cc:40
size_t Read(void *const buff, size_t size)
Definition: file.cc:70
bool WriteLine(const std::string &line)
Definition: file.cc:130
static bool Delete(const char *const name)
Definition: file.cc:36
absl::string_view filename() const
Definition: file.cc:135
int64 ReadToString(std::string *const line, uint64 max_length)
Definition: file.cc:102
size_t WriteString(const std::string &line)
Definition: file.cc:126
bool Close()
Definition: file.cc:48
CpModelProto proto
const std::string name
int64_t int64
uint64_t uint64
const int INFO
Definition: log_severity.h:31
Definition: file.cc:141
absl::Status WriteString(File *file, const absl::string_view &contents, int flags)
Definition: file.cc:184
absl::Status GetContents(const absl::string_view &filename, std::string *output, int flags)
Definition: file.cc:163
int Defaults()
Definition: base/file.h:119
bool ReadFileToString(const absl::string_view &file_name, std::string *output)
Definition: file.cc:201
absl::Status Delete(const absl::string_view &path, int flags)
Definition: file.cc:305
File * OpenOrDie(const absl::string_view &filename, const absl::string_view &mode, int flags)
Definition: file.cc:154
void WriteProtoToASCIIFileOrDie(const google::protobuf::Message &proto, const absl::string_view &file_name)
Definition: file.cc:258
bool WriteProtoToFile(const google::protobuf::Message &proto, const absl::string_view &file_name)
Definition: file.cc:263
absl::Status GetTextProto(const absl::string_view &filename, google::protobuf::Message *proto, int flags)
Definition: file.cc:275
void WriteProtoToFileOrDie(const google::protobuf::Message &proto, const absl::string_view &file_name)
Definition: file.cc:270
bool WriteProtoToASCIIFile(const google::protobuf::Message &proto, const absl::string_view &file_name)
Definition: file.cc:251
absl::Status SetTextProto(const absl::string_view &filename, const google::protobuf::Message &proto, int flags)
Definition: file.cc:285
bool WriteStringToFile(const std::string &data, const absl::string_view &file_name)
Definition: file.cc:205
absl::Status SetBinaryProto(const absl::string_view &filename, const google::protobuf::Message &proto, int flags)
Definition: file.cc:295
bool ReadFileToProto(const absl::string_view &file_name, google::protobuf::Message *proto)
Definition: file.cc:217
absl::Status Exists(const absl::string_view &path, int flags)
Definition: file.cc:313
absl::Status Open(const absl::string_view &filename, const absl::string_view &mode, File **f, int flags)
Definition: file.cc:142
absl::Status SetContents(const absl::string_view &filename, const absl::string_view &contents, int flags)
Definition: file.cc:196
void ReadFileToProtoOrDie(const absl::string_view &file_name, google::protobuf::Message *proto)
Definition: file.cc:246
std::string message
Definition: trace.cc:395