Google OR-Tools: ortools/base/file.cc Source File
41#include "absl/status/status.h"
42#include "absl/strings/str_cat.h"
43#include "absl/strings/string_view.h"
44#include "google/protobuf/io/tokenizer.h"
45#include "google/protobuf/message.h"
46#include "google/protobuf/text_format.h"
49enum class Format { NORMAL_FILE, GZIP_FILE, BZIP2_FILE };
51static Format GetFormatFromName(absl::string_view name) {
52 const int size = name.size();
53 if (size > 4 && name.substr(size - 3) == ".gz") {
55 } else if (size > 5 && name.substr(size - 4) == ".bz2") {
58 return Format::NORMAL_FILE;
62class CFile : public File {
64 CFile(FILE* c_file, absl::string_view name) : File(name), f_(c_file) {}
65 ~CFile() override = default;
68 size_t Read(void* buf, size_t size) override {
69 return fread(buf, 1, size, f_);
73 size_t Write(const void* buf, size_t size) override {
74 return fwrite(buf, 1, size, f_);
78 absl::Status Close(int ) override {
87 absl::Status(absl::StatusCode::kInvalidArgument,
88 absl::StrCat("Could not close file '", name_, "'")));
95 bool Flush() override { return fflush(f_) == 0; }
100 stat(name_.c_str(), &f_stat);
104 bool Open() const override { return f_ != nullptr; }
110class GzFile : public File {
112 GzFile(gzFile gz_file, absl::string_view name) : File(name), f_(gz_file) {}
113 ~GzFile() override = default;
116 size_t Read(void* buf, size_t size) override { return gzread(f_, buf, size); }
119 size_t Write(const void* buf, size_t size) override {
120 return gzwrite(f_, buf, size);
124 absl::Status Close(int ) override {
133 absl::Status(absl::StatusCode::kInvalidArgument,
134 absl::StrCat("Could not close file '", name_, "'")));
141 bool Flush() override { return gzflush(f_, Z_FINISH) == Z_OK; }
146 std::string null_terminated_name = std::string(name_);
148 file = gzopen(null_terminated_name.c_str(), "rb");
150 file = gzopen(null_terminated_name.c_str(), "r");
153 LOG(FATAL) << "Cannot get the size of '" << name_
154 << "': " << strerror(errno);
157 const int kLength = 5 * 1024;
158 unsigned char buffer[kLength];
159 size_t uncompressed_size = 0;
163 bytes_read = gzread(file, buffer, kLength - 1);
164 uncompressed_size += bytes_read;
165 if (bytes_read < kLength - 1) {
170 error_string = gzerror(file, &err);
172 LOG(FATAL) << "Error " << error_string;
181 bool Open() const override { return f_ != nullptr; }
187class Bz2File : public File {
189 Bz2File(BZFILE* bz_file, absl::string_view name) : File(name), f_(bz_file) {}
190 ~Bz2File() override = default;
193 size_t Read(void* buf, size_t size) override {
194 return BZ2_bzread(f_, buf, size);
198 size_t Write(const void* buf, size_t size) override {
199 return BZ2_bzwrite(f_, const_cast<void*>(buf), size);
203 absl::Status Close(int ) override {
215 bool Flush() override { return BZ2_bzflush(f_) == 0; }
220 std::string null_terminated_name = std::string(name_);
222 file = BZ2_bzopen(null_terminated_name.c_str(), "rb");
224 file = BZ2_bzopen(null_terminated_name.c_str(), "r");
227 LOG(FATAL) << "Cannot get the size of '" << name_
228 << "': " << strerror(errno);
231 const int kLength = 5 * 1024;
232 unsigned char buffer[kLength];
233 size_t uncompressed_size = 0;
236 bytes_read = BZ2_bzread(file, buffer, kLength - 1);
237 uncompressed_size += bytes_read;
238 if (bytes_read < kLength - 1) break;
244 bool Open() const override { return f_ != nullptr; }
260File* File::Open(absl::string_view file_name, absl::string_view mode) {
261 std::string null_terminated_name = std::string(file_name);
262 std::string null_terminated_mode = std::string(mode);
264 if (null_terminated_mode == "r") {
265 null_terminated_mode = "rb";
266 } else if (null_terminated_mode == "w") {
267 null_terminated_mode = "wb";
270 const Format format = GetFormatFromName(file_name);
272 case Format::NORMAL_FILE: {
274 fopen(null_terminated_name.c_str(), null_terminated_mode.c_str());
275 if (c_file == nullptr) return nullptr;
276 return new CFile(c_file, file_name);
280 gzopen(null_terminated_name.c_str(), null_terminated_mode.c_str());
281 if (!gz_file) return nullptr;
282 return new GzFile(gz_file, file_name);
284 case Format::BZIP2_FILE: {
285 BZFILE* bz_file = BZ2_bzopen(null_terminated_name.c_str(),
286 null_terminated_mode.c_str());
287 if (!bz_file) return nullptr;
299 if (max_length == 0) return 0;
301 int64_t needed = max_length;
302 int bufsize = (needed < (2 << 20) ? needed : (2 << 20));
304 std::unique_ptr<char[]> buf(new char[bufsize]);
308 nread = Read(buf.get(), (bufsize < needed ? bufsize : needed));
310 line->append(buf.get(), nread);
316 return (nread >= 0 ? static_cast<int64_t>(line->size()) : -1);
320 return Write(str.data(), str.size());
328absl::Status Open(absl::string_view file_name, absl::string_view mode, File** f,
336 return absl::Status(absl::StatusCode::kInvalidArgument,
340File* OpenOrDie(absl::string_view file_name, absl::string_view mode,
343 CHECK_EQ(options, Defaults());
345 CHECK(f != nullptr) << absl::StrCat("Could not open '", file_name, "'");
349absl::StatusOr<std::string> GetContents(absl::string_view path,
352 absl::Status status = GetContents(path, &contents, options);
359absl::Status GetContents(absl::string_view file_name, std::string* output,
363 auto status = file::Open(file_name, "r", &file, options);
364 if (!status.ok()) return status;
366 const int64_t size = file->Size();
367 if (file->ReadToString(output, size) == size) {
368 status.Update(file->Close(options));
372 file->Close(options).IgnoreError();
374 return absl::Status(absl::StatusCode::kInvalidArgument,
375 absl::StrCat("Could not read from '", file_name, "'."));
380 if (options == Defaults() && file != nullptr &&
381 file->Write(contents.data(), contents.size()) == contents.size()) {
385 absl::StatusCode::kInvalidArgument,
386 absl::StrCat("Could not write ", contents.size(), " bytes"));
390 absl::string_view contents, Options options) {
393 auto status = file::Open(file_name, "w", &file, options);
394 if (!status.ok()) return status;
396 status.Update(file->Close(options));
401class NoOpErrorCollector : public google::protobuf::io::ErrorCollector {
403 ~NoOpErrorCollector() override = default;
404 void RecordError(int , int ,
405 absl::string_view ) override {}
410 google::protobuf::Message* proto, Options options) {
414 VLOG(1) << "Could not read '" << file_name << "'";
416 absl::StatusCode::kInvalidArgument,
417 absl::StrCat("Could not read proto from '", file_name, "'."));
426 NoOpErrorCollector error_collector;
427 google::protobuf::TextFormat::Parser parser;
428 parser.RecordErrorsTo(&error_collector);
430 if (parser.ParseFromString(str, proto)) {
434 if (proto->ParseFromString(str)) {
440 google::protobuf::TextFormat::ParseFromString(str, proto);
441 VLOG(1) << "Could not parse contents of '" << file_name << "'";
444 absl::StatusCode::kInvalidArgument,
445 absl::StrCat("Could not read proto from '", file_name, "'."));
449 const google::protobuf::Message& proto,
453 if (google::protobuf::TextFormat::PrintToString(proto, &proto_string) &&
459 absl::StatusCode::kInvalidArgument,
460 absl::StrCat("Could not write proto to '", file_name, "'."));
464 google::protobuf::Message* proto, Options options) {
468 proto->ParseFromString(str)) {
472 absl::StatusCode::kInvalidArgument,
473 absl::StrCat("Could not read proto from '", file_name, "'."));
477 const google::protobuf::Message& proto,
481 if (proto.AppendToString(&proto_string) &&
487 absl::StatusCode::kInvalidArgument,
488 absl::StrCat("Could not write proto to '", file_name, "'."));
491absl::Status Delete(absl::string_view path, Options options) {
493 std::string null_terminated_path = std::string(path);
494 if (remove(null_terminated_path.c_str()) == 0) return absl::OkStatus();
496 return absl::Status(absl::StatusCode::kInvalidArgument,
absl::string_view filename() const
Definition file.cc:323
virtual size_t Write(const void *buf, size_t size)=0
virtual size_t Read(void *buf, size_t size)=0
static void Init()
Definition file.cc:325
static File * OpenOrDie(absl::string_view file_name, absl::string_view mode)
Definition file.cc:254
size_t WriteString(absl::string_view str)
Definition file.cc:319
File(absl::string_view name)
Definition file.cc:252
virtual bool Open() const =0
int64_t ReadToString(std::string *line, uint64_t max_length)
Definition file.cc:295
absl::StatusOr< std::string > GetContents(absl::string_view path, Options options)
Definition file.cc:349
absl::Status Exists(absl::string_view path, Options options)
Definition file.cc:500
absl::Status SetBinaryProto(absl::string_view file_name, const google::protobuf::Message &proto, Options options)
Definition file.cc:476
absl::Status SetTextProto(absl::string_view file_name, const google::protobuf::Message &proto, Options options)
Definition file.cc:448
absl::Status GetTextProto(absl::string_view file_name, google::protobuf::Message *proto, Options options)
Definition file.cc:409
File * OpenOrDie(absl::string_view file_name, absl::string_view mode, Options options)
Definition file.cc:340
absl::Status WriteString(File *file, absl::string_view contents, Options options)
Definition file.cc:378
absl::Status GetBinaryProto(const absl::string_view file_name, google::protobuf::Message *proto, Options options)
Definition file.cc:463
absl::Status Delete(absl::string_view path, Options options)
Definition file.cc:491
absl::Status Open(absl::string_view file_name, absl::string_view mode, File **f, Options options)
Definition file.cc:328
absl::Status SetContents(absl::string_view file_name, absl::string_view contents, Options options)
Definition file.cc:389