1#pragma once 2 3#include <stdio.h> 4#include <fstream> 5#include <memory> 6#include <string> 7#include "absl/strings/string_view.h" 8#include "muduo/base/Logging.h" // CHECK_NOTNULL 9 10const int kBufferSize = 1024 * 1024; 11 12// Wrappers FILE* from stdio. 13class File 14{ 15 public: 16 int64_t tell() const 17 { 18 return ::ftell(file_); 19 } 20 21 void close() 22 { 23 if (file_) 24 ::fclose(file_); 25 file_ = nullptr; 26 buffer_.reset(); 27 } 28 29 const std::string& filename() const 30 { 31 return filename_; 32 } 33 34 // https://github.com/coreutils/coreutils/blob/master/src/ioblksize.h 35 /* As of May 2014, 128KiB is determined to be the minimium 36 * blksize to best minimize system call overhead. 37 */ 38 39 protected: 40 File(const std::string& filename, const char* mode, int bufsize=kBufferSize) 41 : filename_(filename), 42 file_(CHECK_NOTNULL(::fopen(filename.c_str(), mode))), 43 buffer_(CHECK_NOTNULL(new char[bufsize])) 44 { 45 ::setbuffer(file_, buffer_.get(), bufsize); 46 } 47 48 virtual ~File() 49 { 50 close(); 51 } 52 53 protected: 54 std::string filename_; 55 FILE* file_ = nullptr; 56 57 private: 58 std::unique_ptr<char[]> buffer_; 59 60 File(const File&) = delete; 61 void operator=(const File&) = delete; 62}; 63 64class InputFile : public File 65{ 66 public: 67 explicit InputFile(const char* filename, int bufsize=kBufferSize) 68 : File(filename, "r", bufsize) 69 { 70 } 71 72 bool getline(std::string* output) 73 { 74 char buf[1024]; // ="" will slow down by 50%!!! 75 if (::fgets(buf, sizeof buf, file_)) 76 { 77 *output = buf; 78 if (!output->empty() && output->back() == '\n') 79 { 80 output->resize(output->size()-1); 81 } 82 return true; 83 } 84 return false; 85 } 86}; 87 88/* 89class InputFile2 90{ 91 public: 92 explicit InputFile2(const char* filename, int bufsize=kBufferSize) 93 : filename_(filename), 94 in_(filename) 95 { 96 // FIXME: bufsize 97 } 98 99 bool getline(std::string* output) 100 { 101 return static_cast<bool>(std::getline(in_, *output)); 102 } 103 104 const std::string& filename() const 105 { 106 return filename_; 107 } 108 109 private: 110 std::string filename_; 111 std::ifstream in_; 112}; 113*/ 114 115class OutputFile : public File 116{ 117 public: 118 explicit OutputFile(const std::string& filename) 119 : File(filename, "w") 120 { 121 } 122 123 void write(absl::string_view s) 124 { 125 ::fwrite(s.data(), 1, s.size(), file_); 126 } 127 128 void writeWord(int64_t count, absl::string_view word) 129 { 130 ::fprintf(file_, "%ld\t", count); 131 ::fwrite(word.data(), 1, word.size(), file_); 132 ::fwrite("\n", 1, 1, file_); 133 } 134 135 void appendRecord(absl::string_view s) 136 { 137 assert(s.size() < 255); 138 uint8_t len = s.size(); 139 ::fwrite(&len, 1, sizeof len, file_); 140 ::fwrite(s.data(), 1, len, file_); 141 ++items_; 142 } 143 144 size_t items() 145 { 146 return items_; 147 } 148 149 private: 150 size_t items_ = 0; 151}; 152 153