привет, меня зовут Адам Лейт, как я могу использовать это - PullRequest
0 голосов
/ 18 апреля 2020
void SplitFile(string sourcefile, string destinationfile) {
    ifstream fin(sourcefile, ifstream::binary);
    ofstream fout(destinationfile, ofstream::binary);
    fin.seekg(0, fin.end);
    long size = fin.tellg();
    fin.seekg(0, fin.beg);

    delete[]buf;
    fin.close();
    fout.close();
}

откуда я знаю, что этот код может построить
моя идея - прочитать размер исходного файла. затем разделите байт и напишите назначение, но я не знаю, как разделить.

-требования назначения, которые пользователь будет вводить:

MYSPLITFILE -s D: /film.mkv -d D: / par1 -sizeapart 1000000

Имена разделенных частей являются: film.mkv.part01, film.mkv.part02, film.mkv.part03 ...

1 Ответ

0 голосов
/ 18 апреля 2020

Разделить файл обычно просто.

Требования к командной строке усложняют жизнь.

Кроме того, вы можете указать размер частей или их количество. Кроме того, необходимо учитывать, что детали могут быть не одинаковыми по размеру. Если ваш исходный размер файла составляет 20, а вы запрашиваете размер детали 7, то вам нужно написать 3 файла. 2 с 7 байтами и 1 с 6 байтами.

Вы можете использовать целочисленное деление и деление по модулю, чтобы получить эти значения

20 / 7 = 2
20 % 7 = 6

Оценка параметров строки команд является наиболее сложной частью. Для этого я создал отдельную функцию.

Я использую библиотеку C ++ std :: filesystem , чтобы выполнить всю работу, связанную с файлами.

Пожалуйста, посмотрите полный пример. Это пример кода. Это может быть реализовано так в C ++. У Бьюте, конечно, есть много других возможных решений. Но это должно дать вам представление о том, как это может работать.

Вы не поймете это. Он использует особенности C ++. Но не сдавайся рано. Go через это строка за строкой и Google все. Затем вы можете изучить хотя бы эту концепцию и реализовать ее своими словами.

#include <iostream>
#include <fstream>
#include <sstream>
#include <filesystem>
#include <cstdlib>
#include <tuple>
#include <iomanip>
#include <iterator>
#include <algorithm>

constexpr size_t NumberOfArgumentGroups = 3;
constexpr int NumberOfArguments = 7;

namespace fs = std::filesystem;

const std::string parameterExplanation{ "Please invoke program with parameters:\n-s path_of_source_file "
"-d path_of_destination -numpart x\nor\n-s path_of_source_file "
"-d path_of_destination -sizeapart x\n\n" };

std::tuple<bool, fs::path, fs::path, std::uintmax_t, std::uintmax_t> checkProgramArguments(int argc, char* argv[]) {

    bool ok{ true };                // Indicates, if there was an error or not
    fs::path sourceFilePath{};      // Path and file name of source file
    fs::path destinationFilePath{}; // Output directory part
    size_t numberOfParts{};         // So many parts are requested via option
    unsigned long partSize{};       // The outpit file size requested via option

    // First check the overall number of parameters
    if (NumberOfArguments != argc) {
        std::cerr << "\n*** Error:" << parameterExplanation;
        ok = false;
    }
    // Now go through all parameters and check them
    else for (size_t group{}; group < NumberOfArgumentGroups; ++group) {

        // Get the option
        std::string option(argv[group * 2U + 1U]);

        // Specification of source path?
        if ("-s" == option) {
            // Get the source path
            sourceFilePath = argv[group * 2U + 2U];
            // And check, if the file exists and if it is a regurlar file
            if (!fs::exists(sourceFilePath) || !fs::is_regular_file(sourceFilePath)) {
                std::cerr << "\n*** Error: Problem with source file:\n" << sourceFilePath.string() << "\n";
                ok = false;
            }
        }
        // Specification of destination directory?
        else if ("-d" == option) {
            destinationFilePath = argv[group * 2U + 2U];
            // Check, if directory exists
            if (!fs::exists(destinationFilePath) || !fs::is_directory(destinationFilePath)) {
                std::cerr << "\n*** Error: Destination file path does not exist\n" << destinationFilePath.string() << "\n";
                ok = false;
            }
        }
        // Specification of number of parts?
        else if ("-numpart" == option) {
            char* end;
            // Convert to number
            numberOfParts = std::strtoul(argv[group * 2U + 2U], &end, 10);
            if (0 == numberOfParts) {
                std::cerr << "\n*** Error: Invalid parameter for number of parts: " << argv[group * 2U + 2U] << "\n";
                ok = false;
            }
        }
        // Specification of size of one part
        else if ("-sizeapart" == option) {
            char* end;
            // Convert to size number
            partSize = std::strtoul(argv[group * 2U + 2U], &end, 10);
            if (0 == partSize) {
                std::cerr << "\n*** Error: Invalid parameter for number of parts: " << argv[group * 2U + 2U] << "\n";
                ok = false;
            }
        }
        else {
            // Wrong option specified. Error message
            std::cerr << "\n*** Error: Invalid option '" << option << "' specified.\n" << parameterExplanation;
            ok = false;
        }
    }
    // Sanity check,. Test combinations of parameters
    if (sourceFilePath.empty() || destinationFilePath.empty() || ((numberOfParts) > 0 && (partSize > 0))) {
        std::cerr << "\n*** Error: Invalid option combination\n" << parameterExplanation;
        ok = false;
    }
    return { ok, sourceFilePath, destinationFilePath, numberOfParts, partSize };
}


// Driver code
int main(int argc, char* argv[]) {

    // Check and evaluate comand line parameter
    if (const auto& [ok, sourceFile, destinationDirectory, numberParts, sizeOfPart] = checkProgramArguments(argc, argv); ok) {

        // Get the size of the source file
        std::uintmax_t fileSize = fs::file_size(sourceFile);

        // Now we need to calculate 3 parameters. 
        std::uintmax_t numberOfParts{};             // Number of files to create
        std::uintmax_t numberOfBytesForLastPart;    // The last file may contain less bytes
        std::uintmax_t partSize{};                  // Size of one output file (except the last

        // So, either the number of parts of the part size is given. Depending on that
        if (numberParts > 0) {

            // Part number was given. Check, if the file size can be devided in exactly number parts
            if (fileSize % (fileSize / numberParts) != 0)

                // No, cannot. We need to write a lst file with less then part size bytes
                // Therefore, decrement the number of output files with full number of bytes
                numberOfParts = numberParts - 1;
            else 
                // We will write numberParts files with equal number of bytes
                numberOfParts = numberParts;

            // Calculate the size of pne output file
            partSize = fileSize / numberOfParts;

            // And the number of vbytes for the last file
            numberOfBytesForLastPart = fileSize % partSize;
        }
        else {
            // The size of a part was given
            partSize = sizeOfPart;
            // Calculate the number of files that we will write
            numberOfParts = fileSize / sizeOfPart;
            // And the size of the last file
            numberOfBytesForLastPart = fileSize % partSize;
        }

        // Open the input file and check, if it could be opened
        if (std::ifstream sourceFileStream(sourceFile, std::ios::binary); sourceFileStream) {

            // Write all parts
            for (std::uintmax_t i{}; i <= numberOfParts; ++i) {

                // Build the file name for the output file
                std::ostringstream outputFileName{};
                outputFileName << sourceFile.filename().string() << ".part" << std::setfill('0') << std::setw(2) << i+1;
                // This is a smart overload of the / operator. It will concatenate the path and filename with correct delimiter
                fs::path outputFilePathAndName = destinationDirectory / outputFileName.str();

                // DO only something if we have still bytes to copy
                if (uintmax_t bytesToCopy = ((i == numberOfParts) ? numberOfBytesForLastPart : partSize); bytesToCopy > 0) {

                    // Open the output file for this part and check, if it is open
                    if (std::ofstream outputFileStream(outputFilePathAndName, std::ios::binary); outputFileStream) {

                        // Copy bytes from source to destination
                        std::copy_n(std::istreambuf_iterator<char>(sourceFileStream),
                            bytesToCopy,
                            std::ostreambuf_iterator<char>(outputFileStream));
                    }
                }
                else {
                    std::cerr << "\n*** Error: Could not open destination file: " << outputFilePathAndName << "\n";
                }
            }
        }
        else {
            std::cerr << "\n*** Error: Could not open source file: " << sourceFile << "\n";
        }
    }
    return 0;
}

Я добавил много проверок на ошибки. Тебе тоже следует это сделать.

...