BinaryFileReader¶
std::ifstream
を使って、バイナリファイルを読み込むクラスを実装する。
BinaryFileReader.hpp
#pragma once
#include <memory> // std::shared_ptr, std::addressof
#include <string_view> // std::string_view
#include <string> // std::string
#include <type_traits> // std::is_trivially_copyable_v
#include "Common.hpp"
namespace seccamp
{
/// @brief バイナリファイルを読み込むクラス
class BinaryFileReader
{
public:
/// @brief デフォルトコンストラクタ
[[nodiscard]]
BinaryFileReader();
/// @brief ファイルをオープンします。
/// @param path ファイルパス
[[nodiscard]]
explicit BinaryFileReader(std::string_view path);
/// @brief ファイルがオープンされているかを返します。
/// @return オープンされている場合 true, それ以外の場合は false
[[nodiscard]]
bool isOpen() const noexcept;
/// @brief ファイルがオープンされているかを返します。
/// @return オープンされている場合 true, それ以外の場合は false
[[nodiscard]]
explicit operator bool() const noexcept;
/// @brief ファイルをオープンします。すでにオープンされている場合はクローズしてから再オープンします。
/// @param path ファイルパス
/// @return オープンに成功した場合 true, それ以外の場合は false
bool open(std::string_view path);
/// @brief ファイルをクローズします。
void close();
/// @brief ファイルのサイズ(バイト)を返します。
/// @return ファイルのサイズ(バイト)。ファイルがオープンされていない場合は 0
[[nodiscard]]
int64 size() const noexcept;
/// @brief ファイルからデータを読み込みます。
/// @param data 読み込んだデータを格納するバッファ
/// @param size データのサイズ(バイト)
/// @return 読み込んだバイト数
int64 read(void* data, size_t size);
/// @brief ファイルからデータを読み込みます。
/// @tparam T 読み込むデータの型
/// @param data 読み込んだデータを格納する変数
/// @return 読み込んだバイト数
template <class T>
requires std::is_trivially_copyable_v<T>
int64 read(T& data)
{
return read(std::addressof(data), sizeof(T));
}
/// @brief ファイルの絶対パスを返します。
/// @return ファイルの絶対パス。ファイルがオープンされていない場合は空文字列
[[nodiscard]]
const std::string& fullPath() const noexcept;
private:
class Impl;
std::shared_ptr<Impl> m_pImpl;
};
}
BinaryFileReader.cpp
#include <fstream> // std::ifstream
#include "BinaryFileReader.hpp"
#include "FileSystem.hpp"
namespace seccamp
{
namespace
{
/// @brief ファイルのサイズ(バイト)を取得します。
/// @param file ファイル
/// @return ファイルのサイズ(バイト)
[[nodiscard]]
static int64 GetFileSize(std::ifstream& file)
{
const int64 currentPos = file.tellg();
file.seekg(0, std::ios::end);
const int64 size = file.tellg();
file.seekg(currentPos);
return size;
}
}
class BinaryFileReader::Impl
{
public:
Impl() = default;
~Impl()
{
close();
}
[[nodiscard]]
bool isOpen() const noexcept
{
return m_file.is_open();
}
bool open(const std::string_view path)
{
if (m_file.is_open())
{
close();
}
m_file.open(std::string{ path }, std::ios::binary);
if (m_file.is_open())
{
m_fullPath = FileSystem::FullPath(path);
m_size = GetFileSize(m_file);
return true;
}
else
{
return false;
}
}
void close()
{
m_file.close();
m_size = 0;
m_fullPath.clear();
}
[[nodiscard]]
int64 size() const noexcept
{
return m_size;
}
[[nodiscard]]
int64 read(void* data, const size_t size)
{
m_file.read(static_cast<char*>(data), size);
return m_file.gcount();
}
[[nodiscard]]
const std::string& fullPath() const noexcept
{
return m_fullPath;
}
private:
std::ifstream m_file;
int64 m_size = 0;
std::string m_fullPath;
};
BinaryFileReader::BinaryFileReader()
: m_pImpl{ std::make_shared<Impl>() } {}
BinaryFileReader::BinaryFileReader(const std::string_view path)
: BinaryFileReader{} // 移譲コンストラクタ
{
m_pImpl->open(path);
}
bool BinaryFileReader::isOpen() const noexcept
{
return m_pImpl->isOpen();
}
BinaryFileReader::operator bool() const noexcept
{
return m_pImpl->isOpen();
}
bool BinaryFileReader::open(const std::string_view path)
{
return m_pImpl->open(path);
}
void BinaryFileReader::close()
{
m_pImpl->close();
}
int64 BinaryFileReader::size() const noexcept
{
return m_pImpl->size();
}
int64 BinaryFileReader::read(void* data, const size_t size)
{
return m_pImpl->read(data, size);
}
const std::string& BinaryFileReader::fullPath() const noexcept
{
return m_pImpl->fullPath();
}
}
追加のチャレンジ¶
int64 getPos()
/void setPos(int64 pos)
を追加して、読み込み位置を取得・設定できるようにする。int64 read(void* data, int64 pos, size_t size)
を追加して、指定した位置からデータを読み込めるようにする。int64 lookahead(void* data, size_t size)
を追加して、ファイルの読み込み位置を変更せずにデータを読み込めるようにする。int64 lookahead(void* data, int64 pos, size_t size)
を追加して、ファイルの読み込み位置を変更せずに指定した位置からデータを読み込めるようにする。