Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <string_view>
- #include <filesystem>
- #include <cstdio>
- #include <cstring>
- #include <cassert>
- #include <fstream>
- #include <filesystem>
- #include <memory>
- #include "vector"
- /*
- * В данном задании требуется реализовать запись в файл и чтение из файла структуры данных `DataFile`.
- * Для чтения и записи необходимо четыре функции:
- * - `DataFile ReadRawFile(const std::filesystem::path& filename)` -- прочитать данные из файла в структуру DataFile "как есть" побайтово
- * - `void WriteRawFile(const std::filesystem::path& filename, const DataFile& data)` -- записать данные из структуры DataFile в файл "как есть" побайтово
- * - `DataFile ReadCompressedFile(const std::filesystem::path& filename)` -- прочитать сжатые способом RLE данные
- * - `void WriteCompressedFile(const std::filesystem::path& filename, const DataFile& data)` -- записать данные в сжатом способом RLE виде
- *
- * Способ сжатия RLE заключается в замене повторяющихся последовательностей байтов (например, "FFFFFFF") двумя байтами,
- * в первом байте указывая длину последовательности, а второй байт сохраняет исходные данные, которые надо повторить.
- * Например, последовательность "AAAFFFFFFF" превратится в "3A7F". Тут символы 3 и 7 указаны условно, так как на самом деле
- * в файл нужно записать байты, обозначающие числа 3 и 7 в двоичном представлении.
- *
- * Если же в данных встречается последовательность и неповторяющихся байтов (например, "ABCDEF"),
- * то её можно закодировать двумя способами:
- * - "ABCDEF" -> "1A1B1C1D1E1F" (было 6 байтов, стало 12)
- * - "ABCDEF" -> "-6ABCDEF" (было 6 байтов, стало 7).
- * Во втором случае мы приписали в начало последовательности байт со значением '-6', чтобы показать,
- * что далее идет группа из 6 байт, которые не сжаты.
- * Если в файле будет много несжимаемых частей, то второй способ позволяет экономить место.
- */
- struct DataFile {
- char header[40];
- uint64_t version;
- uint64_t importantNumberA, veryImportantNumberB;
- double notSoImportantNumberC;
- char text[50];
- };
- DataFile ReadRawFile(const std::filesystem::path& filename) {
- DataFile data;
- std::ifstream file(filename, std::ios::binary);
- if (!file) {
- throw std::runtime_error("Failed to open file for reading");
- }
- file.read(reinterpret_cast<char*>(&data), sizeof(DataFile));
- return data;
- }
- void WriteRawFile(const std::filesystem::path& filename, const DataFile& data) {
- std::ofstream file(filename, std::ios::binary);
- if (!file) {
- throw std::runtime_error("Failed to open file for write");
- }
- file.write(reinterpret_cast<const char*>(&data), sizeof(DataFile));
- }
- DataFile ReadCompressedFile(const std::filesystem::path& filename) {
- DataFile data;
- std::ifstream file(filename, std::ios::binary);
- if (!file) {
- throw std::runtime_error("Failed to open file for reading");
- }
- file.seekg(0, std::ios::end);
- std::streampos fileSize = file.tellg();
- file.seekg(0, std::ios::beg);
- char* compressedData = new char[fileSize];
- file.read(compressedData, fileSize);
- std::vector<char> Data;
- int index = 0;
- while (index < fileSize) {
- char count = compressedData[index++];
- if (count < 0) {
- count = -count;
- for (int i = 0; i < count; i++) {
- Data.push_back(compressedData[index++]);
- }
- } else {
- char value = compressedData[index++];
- for (int i = 0; i < count; ++i) {
- Data.push_back(value);
- }
- }
- }
- delete[] compressedData;
- memcpy(&data, Data.data(), sizeof(DataFile));
- return data;
- }
- void WriteCompressedFile(const std::filesystem::path& filename, const DataFile& data) {
- std::ofstream file(filename, std::ios::binary);
- if (!file) {
- throw std::runtime_error("Failed to open file for write");
- }
- std::vector<char> compressedData;
- for (int i = 0; i < sizeof(DataFile); ++i) {
- char currchar = reinterpret_cast<const char*>(&data)[i];
- int countcurrchar = 1;
- for (int j = i + 1; j < sizeof(DataFile); ++j) {
- if (reinterpret_cast<const char*>(&data)[j] == currchar) {
- countcurrchar++;
- } else {
- break;
- }
- }
- compressedData.push_back((char)countcurrchar);
- compressedData.push_back(currchar);
- i += countcurrchar - 1;
- }
- // Write the compressed data to file
- file.write(compressedData.data(), compressedData.size());
- }
- // Код, помогающий в отладке
- bool operator ==(const DataFile& lhs, const DataFile& rhs) {
- return std::memcmp((void*)&lhs, (void*)&rhs, sizeof(DataFile)) == 0;
- }
- int main() {
- const DataFile data = {
- "Cool file.", 1, 100, (uint64_t)-1, 3.1415, "Lorem ipsum dolor..."
- };
- const std::filesystem::path rawDataFilename = std::filesystem::temp_directory_path() / "cpp_task.dat";
- const std::filesystem::path compressedDataFilename = std::filesystem::temp_directory_path() / "cpp_task.dat.rle";
- WriteRawFile(rawDataFilename, data);
- assert(std::filesystem::exists(rawDataFilename));
- DataFile dataFromRawFile = ReadRawFile(rawDataFilename);
- assert(data.veryImportantNumberB == dataFromRawFile.veryImportantNumberB);
- assert(std::string_view(data.text) == std::string_view(dataFromRawFile.text));
- assert(std::string_view(data.header) == std::string_view(dataFromRawFile.header));
- assert(data == dataFromRawFile);
- assert(std::filesystem::file_size(rawDataFilename) == sizeof(data));
- std::cout << "Raw file size: " << std::filesystem::file_size(rawDataFilename) << " bytes" << std::endl;
- std::filesystem::remove(rawDataFilename);
- WriteCompressedFile(compressedDataFilename, data);
- assert(std::filesystem::exists(compressedDataFilename));
- DataFile dataFromCompressedFile = ReadCompressedFile(compressedDataFilename);
- assert(data.veryImportantNumberB == dataFromCompressedFile.veryImportantNumberB);
- assert(std::string_view(data.text) == std::string_view(dataFromCompressedFile.text));
- assert(std::string_view(data.header) == std::string_view(dataFromCompressedFile.header));
- assert(data == dataFromCompressedFile);
- assert(std::filesystem::file_size(compressedDataFilename) * 2 <= sizeof(data));
- std::cout << "Compressed file size: " << std::filesystem::file_size(compressedDataFilename) << " bytes" << std::endl;
- std::filesystem::remove(compressedDataFilename);
- }
Advertisement
Add Comment
Please, Sign In to add comment