-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmerge_engine.cpp
More file actions
148 lines (125 loc) · 5.13 KB
/
Copy pathmerge_engine.cpp
File metadata and controls
148 lines (125 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <dirent.h>
#include <sys/stat.h>
#ifdef _WIN32
#include <windows.h>
#endif
/**
* AUTO-DISCOVER SHARDS (Windows Compatible)
* Finds all shard files matching the pattern and sorts them in correct order.
* @param base_path: The base path used when splitting (e.g., "output/data").
* @return A sorted vector of shard file paths.
*/
std::vector<std::string> discover_shards(const std::string& base_path) {
std::vector<std::string> shard_paths;
// Extract directory and filename prefix
size_t last_slash = base_path.find_last_of("/\\");
std::string dir = (last_slash != std::string::npos) ? base_path.substr(0, last_slash) : ".";
std::string prefix = (last_slash != std::string::npos) ? base_path.substr(last_slash + 1) : base_path;
#ifdef _WIN32
// Windows implementation using WIN32 API
std::string search_pattern = dir + "\\*.*";
WIN32_FIND_DATAA find_data;
HANDLE hFind = FindFirstFileA(search_pattern.c_str(), &find_data);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
std::string filename = find_data.cFileName;
// Check if filename starts with prefix and ends with .bin
std::string expected_start = prefix + "_shard_";
if (filename.find(expected_start) == 0 &&
filename.length() >= 4 &&
filename.substr(filename.length() - 4) == ".bin") {
shard_paths.push_back(dir + "\\" + filename);
}
}
} while (FindNextFileA(hFind, &find_data) != 0);
FindClose(hFind);
}
#else
// POSIX implementation using dirent.h
DIR* directory = opendir(dir.c_str());
if (directory) {
struct dirent* entry;
while ((entry = readdir(directory)) != nullptr) {
std::string filename = entry->d_name;
std::string expected_start = prefix + "_shard_";
if (filename.find(expected_start) == 0 &&
filename.length() >= 4 &&
filename.substr(filename.length() - 4) == ".bin") {
shard_paths.push_back(dir + "/" + filename);
}
}
closedir(directory);
}
#endif
// Sort shards lexicographically (thanks to zero-padding, this gives correct order)
std::sort(shard_paths.begin(), shard_paths.end());
return shard_paths;
}
/**
* SEQUENTIAL MERGE FUNCTION
* @param shard_paths: A list of full paths to the .bin shards in correct order.
* @param output_path: Where to save the reconstructed original file.
* @return true if successful, false otherwise.
*/
bool merge_shards(const std::vector<std::string>& shard_paths, const std::string& output_path) {
if (shard_paths.empty()) {
std::cerr << "Error: No shards provided for merging." << std::endl;
return false;
}
std::ofstream final_file(output_path, std::ios::binary);
if (!final_file.is_open()) {
std::cerr << "Error: Could not create output file at " << output_path << std::endl;
return false;
}
size_t total_bytes = 0;
int shard_count = 0;
for (const std::string& path : shard_paths) {
std::ifstream shard(path, std::ios::binary);
if (shard.is_open()) {
// Get file size
shard.seekg(0, std::ios::end);
size_t size = shard.tellg();
shard.seekg(0, std::ios::beg);
// Efficiently copy the shard buffer into the final file
final_file << shard.rdbuf();
shard.close();
total_bytes += size;
shard_count++;
std::cout << "Merged: " << path << " (" << size << " bytes)" << std::endl;
} else {
std::cerr << "Error: Shard missing or unreadable: " << path << std::endl;
final_file.close();
return false;
}
}
final_file.close();
std::cout << "Merge complete! Wrote " << total_bytes << " bytes from " << shard_count << " shards." << std::endl;
return true;
}
int main(int argc, char* argv[]) {
if (argc < 3) {
std::cout << "Usage: " << argv[0] << " <base_path> <output_file>" << std::endl;
std::cout << "Example: " << argv[0] << " output/data reconstructed.txt" << std::endl;
return 1;
}
std::string base_path = argv[1];
std::string output_path = argv[2];
// Auto-discover shard files
std::cout << "Discovering shards matching pattern: " << base_path << "_shard_*.bin" << std::endl;
std::vector<std::string> shards = discover_shards(base_path);
if (shards.empty()) {
std::cerr << "Error: No shard files found!" << std::endl;
return 1;
}
std::cout << "Found " << shards.size() << " shards." << std::endl;
if (!merge_shards(shards, output_path)) {
return 1;
}
return 0;
}