keker123

Untitled

May 27th, 2023
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.42 KB | None | 0 0
  1. #include <iostream>
  2. #include <string_view>
  3. #include <filesystem>
  4. #include <cstdio>
  5. #include <cstring>
  6. #include <cassert>
  7. #include <fstream>
  8. #include <filesystem>
  9. #include <memory>
  10. #include "vector"
  11.  
  12. /*
  13. * В данном задании требуется реализовать запись в файл и чтение из файла структуры данных `DataFile`.
  14. * Для чтения и записи необходимо четыре функции:
  15. * - `DataFile ReadRawFile(const std::filesystem::path& filename)` -- прочитать данные из файла в структуру DataFile "как есть" побайтово
  16. * - `void WriteRawFile(const std::filesystem::path& filename, const DataFile& data)` -- записать данные из структуры DataFile в файл "как есть" побайтово
  17. * - `DataFile ReadCompressedFile(const std::filesystem::path& filename)` -- прочитать сжатые способом RLE данные
  18. * - `void WriteCompressedFile(const std::filesystem::path& filename, const DataFile& data)` -- записать данные в сжатом способом RLE виде
  19. *
  20. * Способ сжатия RLE заключается в замене повторяющихся последовательностей байтов (например, "FFFFFFF") двумя байтами,
  21. * в первом байте указывая длину последовательности, а второй байт сохраняет исходные данные, которые надо повторить.
  22. * Например, последовательность "AAAFFFFFFF" превратится в "3A7F". Тут символы 3 и 7 указаны условно, так как на самом деле
  23. * в файл нужно записать байты, обозначающие числа 3 и 7 в двоичном представлении.
  24. *
  25. * Если же в данных встречается последовательность и неповторяющихся байтов (например, "ABCDEF"),
  26. * то её можно закодировать двумя способами:
  27. * - "ABCDEF" -> "1A1B1C1D1E1F" (было 6 байтов, стало 12)
  28. * - "ABCDEF" -> "-6ABCDEF" (было 6 байтов, стало 7).
  29. * Во втором случае мы приписали в начало последовательности байт со значением '-6', чтобы показать,
  30. * что далее идет группа из 6 байт, которые не сжаты.
  31. * Если в файле будет много несжимаемых частей, то второй способ позволяет экономить место.
  32. */
  33.  
  34. struct DataFile {
  35. char header[40];
  36. uint64_t version;
  37. uint64_t importantNumberA, veryImportantNumberB;
  38. double notSoImportantNumberC;
  39. char text[50];
  40. };
  41.  
  42. DataFile ReadRawFile(const std::filesystem::path& filename) {
  43. DataFile data;
  44. std::ifstream file(filename, std::ios::binary);
  45. if (!file) {
  46. throw std::runtime_error("Failed to open file for reading");
  47. }
  48. file.read(reinterpret_cast<char*>(&data), sizeof(DataFile));
  49. return data;
  50. }
  51.  
  52. void WriteRawFile(const std::filesystem::path& filename, const DataFile& data) {
  53. std::ofstream file(filename, std::ios::binary);
  54. if (!file) {
  55. throw std::runtime_error("Failed to open file for write");
  56. }
  57. file.write(reinterpret_cast<const char*>(&data), sizeof(DataFile));
  58. }
  59.  
  60. DataFile ReadCompressedFile(const std::filesystem::path& filename) {
  61. DataFile data;
  62. std::ifstream file(filename, std::ios::binary);
  63. if (!file) {
  64. throw std::runtime_error("Failed to open file for reading");
  65. }
  66. file.seekg(0, std::ios::end);
  67. std::streampos fileSize = file.tellg();
  68. file.seekg(0, std::ios::beg);
  69. char* compressedData = new char[fileSize];
  70. file.read(compressedData, fileSize);
  71. std::vector<char> Data;
  72. int index = 0;
  73. while (index < fileSize) {
  74. char count = compressedData[index++];
  75. if (count < 0) {
  76. count = -count;
  77. for (int i = 0; i < count; i++) {
  78. Data.push_back(compressedData[index++]);
  79. }
  80. } else {
  81. char value = compressedData[index++];
  82. for (int i = 0; i < count; ++i) {
  83. Data.push_back(value);
  84. }
  85. }
  86. }
  87. delete[] compressedData;
  88. memcpy(&data, Data.data(), sizeof(DataFile));
  89. return data;
  90. }
  91.  
  92. void WriteCompressedFile(const std::filesystem::path& filename, const DataFile& data) {
  93. std::ofstream file(filename, std::ios::binary);
  94. if (!file) {
  95. throw std::runtime_error("Failed to open file for write");
  96. }
  97. std::vector<char> compressedData;
  98. for (int i = 0; i < sizeof(DataFile); ++i) {
  99. char currchar = reinterpret_cast<const char*>(&data)[i];
  100. int countcurrchar = 1;
  101. for (int j = i + 1; j < sizeof(DataFile); ++j) {
  102. if (reinterpret_cast<const char*>(&data)[j] == currchar) {
  103. countcurrchar++;
  104. } else {
  105. break;
  106. }
  107. }
  108. compressedData.push_back((char)countcurrchar);
  109. compressedData.push_back(currchar);
  110. i += countcurrchar - 1;
  111. }
  112. // Write the compressed data to file
  113. file.write(compressedData.data(), compressedData.size());
  114. }
  115.  
  116.  
  117. // Код, помогающий в отладке
  118.  
  119. bool operator ==(const DataFile& lhs, const DataFile& rhs) {
  120. return std::memcmp((void*)&lhs, (void*)&rhs, sizeof(DataFile)) == 0;
  121. }
  122.  
  123.  
  124.  
  125. int main() {
  126. const DataFile data = {
  127. "Cool file.", 1, 100, (uint64_t)-1, 3.1415, "Lorem ipsum dolor..."
  128. };
  129.  
  130. const std::filesystem::path rawDataFilename = std::filesystem::temp_directory_path() / "cpp_task.dat";
  131. const std::filesystem::path compressedDataFilename = std::filesystem::temp_directory_path() / "cpp_task.dat.rle";
  132.  
  133. WriteRawFile(rawDataFilename, data);
  134. assert(std::filesystem::exists(rawDataFilename));
  135.  
  136. DataFile dataFromRawFile = ReadRawFile(rawDataFilename);
  137. assert(data.veryImportantNumberB == dataFromRawFile.veryImportantNumberB);
  138. assert(std::string_view(data.text) == std::string_view(dataFromRawFile.text));
  139. assert(std::string_view(data.header) == std::string_view(dataFromRawFile.header));
  140. assert(data == dataFromRawFile);
  141.  
  142. assert(std::filesystem::file_size(rawDataFilename) == sizeof(data));
  143. std::cout << "Raw file size: " << std::filesystem::file_size(rawDataFilename) << " bytes" << std::endl;
  144. std::filesystem::remove(rawDataFilename);
  145.  
  146. WriteCompressedFile(compressedDataFilename, data);
  147. assert(std::filesystem::exists(compressedDataFilename));
  148.  
  149. DataFile dataFromCompressedFile = ReadCompressedFile(compressedDataFilename);
  150. assert(data.veryImportantNumberB == dataFromCompressedFile.veryImportantNumberB);
  151. assert(std::string_view(data.text) == std::string_view(dataFromCompressedFile.text));
  152. assert(std::string_view(data.header) == std::string_view(dataFromCompressedFile.header));
  153. assert(data == dataFromCompressedFile);
  154.  
  155. assert(std::filesystem::file_size(compressedDataFilename) * 2 <= sizeof(data));
  156. std::cout << "Compressed file size: " << std::filesystem::file_size(compressedDataFilename) << " bytes" << std::endl;
  157. std::filesystem::remove(compressedDataFilename);
  158. }
Advertisement
Add Comment
Please, Sign In to add comment