Mantid
Loading...
Searching...
No Matches
BinaryFile.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#pragma once
8
9#include "MantidKernel/DllConfig.h"
10
11#include <Poco/File.h>
12#include <Poco/Path.h>
13#include <fstream>
14#include <memory>
15#include <string>
16#include <vector>
17
18namespace Mantid {
19namespace Kernel {
20
22static const size_t DEFAULT_BLOCK_SIZE = 100000; // 100,000
23
25static const size_t MAX_BLOCK_SIZE = 100000000; // 100 million
26
28static const size_t MIN_BLOCK_SIZE = 1000;
29
44template <typename T> class DLLExport BinaryFile {
45public:
46 //------------------------------------------------------------------------------------
48 BinaryFile() : handle(nullptr), num_elements(0), offset(0) {}
49
50 //------------------------------------------------------------------------------------
52 BinaryFile(std::string filename) { this->open(filename); }
53
55 ~BinaryFile() { this->close(); }
56
57 //------------------------------------------------------------------------------------
64 void open(const std::string &filename) {
65 this->handle.reset(nullptr);
66 if (!Poco::File(filename).exists()) {
67 std::stringstream msg;
68 msg << "BinaryFile::open: File " << filename << " was not found.";
69 throw std::invalid_argument("File does not exist.");
70 }
71 // Open the file
72 this->handle = std::make_unique<std::ifstream>(filename.c_str(), std::ios::binary);
73 // Count the # of elements.
74 this->num_elements = this->getFileSize();
75 // Make sure we are starting at 0
76 this->offset = 0;
77 }
78
79 //------------------------------------------------------------------------------------
82 void close() { handle.reset(nullptr); }
83
84 //-----------------------------------------------------------------------------
86 size_t getNumElements() const { return this->num_elements; }
87
89 size_t getOffset() const { return this->offset; }
90
91 //-----------------------------------------------------------------------------
96 size_t getBufferSize(const size_t num_items) const {
97 if (num_items < DEFAULT_BLOCK_SIZE)
98 return num_items;
99 else
100 return DEFAULT_BLOCK_SIZE;
101 }
102
103 //-----------------------------------------------------------------------------
109 std::vector<T> loadAll() {
110 if (!handle) {
111 throw std::runtime_error("BinaryFile: file is not open.");
112 }
113
114 // Initialize the pointer
115 std::vector<T> data;
116
117 // A buffer to load from
118 size_t buffer_size = getBufferSize(num_elements);
119 auto buffer = std::make_unique<T[]>(buffer_size);
120
121 // Make sure we are at the beginning
122 offset = 0;
123 handle->seekg(0, std::ios::beg);
124
125 while (offset < num_elements) {
126 // Load that block of data
127 const auto loaded_size = loadBlock(buffer.get(), buffer_size);
128 // Insert into the data
129 data.insert(data.end(), buffer.get(), std::next(buffer.get(), loaded_size));
130 }
131
132 // Close the file, since we are done.
133 this->close();
134
135 // Here's your vector!
136 return data;
137 }
138
139 //-----------------------------------------------------------------------------
145 std::vector<T> loadAllIntoVector() {
146 if (!handle) {
147 throw std::runtime_error("BinaryFile: file is not open.");
148 }
149 std::vector<T> data;
150
151 // A buffer to load from
152 size_t buffer_size = getBufferSize(num_elements);
153 auto buffer = new T[buffer_size];
154
155 // Make sure we are at the beginning
156 offset = 0;
157 handle->seekg(0, std::ios::beg);
158
159 while (offset < num_elements) {
160 // Load that block of data
161 const auto loaded_size = loadBlock(buffer, buffer_size);
162 // Insert into the data
163 data.insert(data.end(), buffer, (buffer + loaded_size));
164 }
165
166 // Close the file, since we are done.
167 this->close();
168 // Free memory
169 delete[] buffer;
170
171 return data;
172 }
173
174 //-----------------------------------------------------------------------------
186 size_t loadBlock(T *buffer, size_t block_size) {
187 if (!handle) {
188 throw std::runtime_error("BinaryFile: file is not open.");
189 }
190
191 size_t loaded_size;
192 // Limit how much is loaded
193 loaded_size = block_size;
194 if (offset + loaded_size > num_elements)
195 loaded_size = num_elements - offset;
196 // Read it right into the buffer
197 handle->read(reinterpret_cast<char *>(buffer), loaded_size * obj_size);
198 offset += loaded_size;
199 return loaded_size;
200 }
201
202 //-----------------------------------------------------------------------------
215 size_t loadBlockAt(T *buffer, size_t newOffset, size_t block_size) {
216 if (!handle) {
217 throw std::runtime_error("BinaryFile: file is not open.");
218 }
219 // Change our offset to the new spot.
220 offset = newOffset;
221 handle->seekg(sizeof(T) * offset, std::ios::beg);
222 return loadBlock(buffer, block_size);
223 }
224
225private:
231 size_t getFileSize() {
232 this->obj_size = sizeof(T);
233
234 if (!handle) {
235 throw std::runtime_error("BinaryFile::getFileSize: Cannot find the size "
236 "of a file from a null handle");
237 }
238
239 // get the size of the file in bytes and reset the handle back to the
240 // beginning
241 handle->seekg(0, std::ios::end);
242 size_t filesize = static_cast<size_t>(handle->tellg());
243 handle->seekg(0, std::ios::beg);
244
245 // check the file is a compatible size
246 if (filesize % obj_size != 0) {
247 std::stringstream msg;
248 msg << "BinaryFile::getFileSize: File size is not compatible with data "
249 "size ";
250 msg << filesize << "%" << obj_size << "=";
251 msg << filesize % obj_size;
252 throw std::runtime_error(msg.str());
253 }
254
255 return filesize / sizeof(T);
256 }
257
259 std::unique_ptr<std::ifstream> handle;
261 size_t obj_size;
265 size_t offset;
266};
267
268} // Namespace Kernel
269
270} // Namespace Mantid
#define DLLExport
Definitions of the DLLImport compiler directives for MSVC.
Definition: System.h:53
The BinaryFile template is a helper function for loading simple binary files.
Definition: BinaryFile.h:44
void open(const std::string &filename)
Open a file and keep a handle to the file.
Definition: BinaryFile.h:64
size_t getFileSize()
Get the size of a file as a multiple of a particular data type.
Definition: BinaryFile.h:231
size_t loadBlock(T *buffer, size_t block_size)
Loads a single block from file and returns a pointer to a vector containing it.
Definition: BinaryFile.h:186
size_t obj_size
Size of each object.
Definition: BinaryFile.h:261
size_t getNumElements() const
Returns the # of elements in the file (cached result of getFileSize)
Definition: BinaryFile.h:86
BinaryFile()
Empty constructor.
Definition: BinaryFile.h:48
std::unique_ptr< std::ifstream > handle
File stream.
Definition: BinaryFile.h:259
size_t offset
Offset into the file, if loading in blocks.
Definition: BinaryFile.h:265
size_t getOffset() const
Returns the current offset into the file.
Definition: BinaryFile.h:89
size_t loadBlockAt(T *buffer, size_t newOffset, size_t block_size)
Loads a single block from file and returns a pointer to a vector containing it.
Definition: BinaryFile.h:215
std::vector< T > loadAll()
Loads the entire contents of the file into a pointer to a std::vector.
Definition: BinaryFile.h:109
void close()
Close the file.
Definition: BinaryFile.h:82
~BinaryFile()
Destructor, close the file if needed.
Definition: BinaryFile.h:55
size_t num_elements
Number of elements of size T in the file.
Definition: BinaryFile.h:263
size_t getBufferSize(const size_t num_items) const
Get a buffer size for loading blocks of data.
Definition: BinaryFile.h:96
BinaryFile(std::string filename)
Constructor - open a file.
Definition: BinaryFile.h:52
std::vector< T > loadAllIntoVector()
Loads the entire contents of the file into a std::vector.
Definition: BinaryFile.h:145
bool exists(::NeXus::File &file, const std::string &name)
Based on the current group in the file, does the named sub-entry exist?
static const size_t DEFAULT_BLOCK_SIZE
Default number of items to read in from any of the files.
Definition: BinaryFile.h:22
static const size_t MIN_BLOCK_SIZE
Min size of a block (too small is inefficient)
Definition: BinaryFile.h:28
static const size_t MAX_BLOCK_SIZE
Max size block to read from a file (memory limitations)
Definition: BinaryFile.h:25
Helper class which provides the Collimation Length for SANS instruments.