コンテンツにスキップ

BinaryFileWriter

  • std::ofstream を使って、バイナリファイルを書き出すクラスを実装する。
BinaryFileWriter.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 BinaryFileWriter
	{
	public:

		/// @brief デフォルトコンストラクタ
		[[nodiscard]]
		BinaryFileWriter();
		
		/// @brief ファイルを作成してオープンします。
		/// @param path ファイルパス
		[[nodiscard]]
		explicit BinaryFileWriter(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 ファイルにデータを書き込みます。
		/// @param data 書き込むデータ
		/// @param size データのサイズ(バイト)
		void write(const void* data, size_t size);

		/// @brief ファイルにデータを書き込みます。
		/// @tparam T 書き込むデータの型
		/// @param data 書き込むデータ
		template <class T>
			requires std::is_trivially_copyable_v<T>
		void write(const T& data)
		{
			write(std::addressof(data), sizeof(T));
		}

		/// @brief ファイルの絶対パスを返します。
		/// @return ファイルの絶対パス。ファイルがオープンされていない場合は空文字列
		[[nodiscard]]
		const std::string& fullPath() const noexcept;

	private:

		class Impl;

		std::shared_ptr<Impl> m_pImpl;
	};
}
BinaryFileWriter.cpp
#include <fstream> // std::ofstream
#include "BinaryFileWriter.hpp"
#include "FileSystem.hpp"

namespace seccamp
{
	class BinaryFileWriter::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);
				
				return true;
			}
			else
			{
				return false;
			}
		}

		void close()
		{
			m_file.close();

			m_fullPath.clear();
		}

		void write(const void* data, const size_t size)
		{
			m_file.write(static_cast<const char*>(data), size);
		}

		[[nodiscard]]
		const std::string& fullPath() const noexcept
		{
			return m_fullPath;
		}

	private:

		std::ofstream m_file;

		std::string m_fullPath;
	};

	BinaryFileWriter::BinaryFileWriter()
		: m_pImpl{ std::make_shared<Impl>() } {}

	BinaryFileWriter::BinaryFileWriter(const std::string_view path)
		: BinaryFileWriter{} // 移譲コンストラクタ
	{
		m_pImpl->open(path);
	}

	bool BinaryFileWriter::isOpen() const noexcept
	{
		return m_pImpl->isOpen();
	}

	BinaryFileWriter::operator bool() const noexcept
	{
		return m_pImpl->isOpen();
	}

	bool BinaryFileWriter::open(const std::string_view path)
	{
		return m_pImpl->open(path);
	}

	void BinaryFileWriter::close()
	{
		m_pImpl->close();
	}

	const std::string& BinaryFileWriter::fullPath() const noexcept
	{
		return m_pImpl->fullPath();
	}

	void BinaryFileWriter::write(const void* data, const size_t size)
	{
		m_pImpl->write(data, size);
	}
}