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"
32
33File::File(FILE* const f_des, const absl::string_view& name)
34 : f_(f_des), name_(name) {}
35
36bool File::Delete(const char* const name) { return remove(name) == 0; }
37
38bool File::Exists(const char* const name) { return access(name, F_OK) == 0; }
39
40size_t File::Size() {
41 struct stat f_stat;
42 stat(name_.data(), &f_stat);
43 return f_stat.st_size;
44}
45
46bool File::Flush() { return fflush(f_) == 0; }
47
49 if (fclose(f_) == 0) {
50 f_ = NULL;
51 return true;
52 } else {
53 return false;
54 }
55}
56
57absl::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
66void File::ReadOrDie(void* const buf, size_t size) {
67 CHECK_EQ(fread(buf, 1, size, f_), size);
68}
69
70size_t File::Read(void* const buf, size_t size) {
71 return fread(buf, 1, size, f_);
72}
73
74void File::WriteOrDie(const void* const buf, size_t size) {
75 CHECK_EQ(fwrite(buf, 1, size, f_), size);
76}
77size_t File::Write(const void* const buf, size_t size) {
78 return fwrite(buf, 1, size, f_);
79}
80
81File* 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
91File* 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
98char* File::ReadLine(char* const output, uint64 max_length) {
99 return fgets(output, max_length, f_);
100}
101
102int64 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
126size_t File::WriteString(const std::string& line) {
127 return Write(line.c_str(), line.size());
128}
129
130bool 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
135absl::string_view File::filename() const { return name_; }
136
137bool File::Open() const { return f_ != NULL; }
138
139void File::Init() {}
140
141namespace file {
142absl::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
154File* 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
163absl::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
184absl::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
196absl::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
201bool ReadFileToString(const absl::string_view& file_name, std::string* output) {
202 return GetContents(file_name, output, file::Defaults()).ok();
203}
204
205bool WriteStringToFile(const std::string& data,
206 const absl::string_view& file_name) {
207 return SetContents(file_name, data, file::Defaults()).ok();
208}
209
210namespace {
211class NoOpErrorCollector : public google::protobuf::io::ErrorCollector {
212 public:
213 virtual void AddError(int line, int column, const std::string& message) {}
214};
215} // namespace
216
217bool 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
246void ReadFileToProtoOrDie(const absl::string_view& file_name,
247 google::protobuf::Message* proto) {
248 CHECK(ReadFileToProto(file_name, proto)) << "file_name: " << file_name;
249}
250
251bool 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
258void 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
263bool 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
270void 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
275absl::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
285absl::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
295absl::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
305absl::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
313absl::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
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
int Defaults()
Definition: base/file.h:119
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