Jag funderade ut pseudokod och bad sedan Gemini Flash 2.0. Thinking att ge något som i princip concatenate filer men först med metadata för att sedan också kunna splitta ut dessa. För att inte tugga igenom varje fil bara för att få veta dess längd så bad jag den att nyttja OS:et filsystem för det borde ju redan sitta på den informationen såsom längd i bytes, filnamn och filändelse.
Den hopsatta filen - om C++-koden kompilerar (vilket den troligen aldrig kan göra från LLM:er!) - ska då innehålla metadata om filnamn, bytes-längd vilket då kan användas som avskiljare när den skriver ut de separata filerna igen. Först tänkte jag på att föra in extra bytes som avskiljare mellan filerna men då finns risken att samma bytes redan används i någon fil som då skulle avskilja vid fel ställe och därmed skapa korrupta filer. Så metadata i början av den stora filen bör lösa det problemet.
Den använder en Struct som innehåller filnamn och bytes-längd och sedan nyttjas en vektor för att lagra metadata av den typen av Struct. Programmet ska köras med att skicka minst 3 argument till den kompilerade "konsolfilen.exe" via char* argv.
Kika gärna och se om det skapar inspiration. Förhoppningsvis ligger prestandan på O(n) där n är antalet filer som ska slås ihop (jag kan ej yttra mig om huruvida den kan innehålla minnesläckor eller ej):
// WARNING: This was written Gemini Flash 2.0 Thinking after prompt from a Junior Web Developer
// This means the code is probably worse than code written by someone who has never seen a line of code before!
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <filesystem> // Requires C++17
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/stat.h>
#endif
namespace fs = std::filesystem;
// Structure to hold file metadata
struct FileInfo {
std::string name;
uint64_t size;
};
// Function to get the size of a file
uint64_t getFileSize(const std::string& filename) {
#ifdef _WIN32
WIN32_FILE_ATTRIBUTE_DATA fileData;
if (GetFileAttributesEx(filename.c_str(), GetFileExInfoStandard, &fileData)) {
return (static_cast<uint64_t>(fileData.nFileSizeHigh) << 32) | fileData.nFileSizeLow;
}
return 0; // Error case
#else
struct stat stat_buf;
int rc = stat(filename.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : 0; // Error case
#endif
}
int main(int argc, char* argv) {
if (argc < 3) {
std::cerr << "Usage: " << argv[0] << " <output_file> <input_file1> [input_file2 ...]" << std::endl;
return 1;
}
std::string outputFilename = argv[1];
std::vector<std::string> inputFilenames;
for (int i = 2; i < argc; ++i) {
inputFilenames.push_back(argv[i]);
}
std::ofstream outputFile(outputFilename, std::ios::binary);
if (!outputFile.is_open()) {
std::cerr << "Error opening output file: " << outputFilename << std::endl;
return 1;
}
// 1. Write the number of files
uint32_t numFiles = static_cast<uint32_t>(inputFilenames.size());
outputFile.write(reinterpret_cast<const char*>(&numFiles), sizeof(numFiles));
// 2. Extract and write metadata
std::vector<FileInfo> fileInfos;
for (const std::string& inputFilename : inputFilenames) {
uint64_t fileSize = getFileSize(inputFilename);
fileInfos.push_back({fs::path(inputFilename).filename().string(), fileSize});
// Write filename (size + content)
uint32_t nameLength = static_cast<uint32_t>(fileInfos.back().name.length());
outputFile.write(reinterpret_cast<const char*>(&nameLength), sizeof(nameLength));
outputFile.write(fileInfos.back().name.c_str(), nameLength);
// Write file size
outputFile.write(reinterpret_cast<const char*>(&fileInfos.back().size), sizeof(fileInfos.back().size));
}
// 3. Concatenate file contents
for (const std::string& inputFilename : inputFilenames) {
std::ifstream inputFile(inputFilename, std::ios::binary);
if (!inputFile.is_open()) {
std::cerr << "Error opening input file: " << inputFilename << std::endl;
outputFile.close();
return 1;
}
char buffer[4096]; // Using a buffer for efficiency
while (inputFile.read(buffer, sizeof(buffer))) {
outputFile.write(buffer, inputFile.gcount());
}
inputFile.close();
std::cout << "Concatenated: " << inputFilename << std::endl;
}
outputFile.close();
std::cout << "Successfully concatenated files into: " << outputFilename << std::endl;
return 0;
}
Dold text
Du får gärna berätta vad möjligen även är segt med denna LLM-lösning kontra kompressionsmjukvarors sätt att slå samman filer. I det sistnämnda tänker jag att de vill tugga igenom varje fil för att kunna komprimera vid behov vilket kanske är en delorsak till varför de är segare än om vi redan vet längden på varje fil och inte vill komprimera dem?
Mvh,
WKF.