Декодирование / кодирование текстового файла с использованием библиотеки стеков - невозможно кодировать большие файлы C++

Я работаю над программой, которая может кодировать, а затем декодировать текст в C++. Я использую библиотеку стека. Программа работает так, что сначала она запрашивает ключ шифра, который вы вводите вручную. Затем он запрашивает имя файла, который является текстовым файлом. Если это обычный текстовый файл, он кодирует сообщение в новый файл и добавляет расширение.iia. Если текстовый файл уже имеет расширение.iia, он декодирует сообщение, если ключ шифрования совпадает с ключом, использованным для его кодирования.

Моя программа кодирует и декодирует, но сколько символов она декодирует, определяется temp.size() % cypher.length() то есть в то время как цикл в readFileEncode() функция. Я думаю, что именно это удерживает весь файл от того, чтобы быть закодированным и затем декодированным правильно. Другими словами, в конечном файле после того, как он был декодирован, скажем, из "example.txt.iia" обратно в "example.txt", отсутствует большая часть текста из исходного файла "example.txt". Я пытался просто cypher.length() но, конечно, тогда ничего не кодируется и не декодируется. Весь процесс определяется этим аргументом для декодирования и кодирования.

Я не могу найти точную логику для этого, чтобы кодировать и декодировать все символы в файле любого размера. Вот следующий код для функции, которая выполняет декодирование и кодирование:

РЕДАКТИРОВАТЬ: Используя код WhozCraig, который он отредактировал для меня:

void readFileEncode(string fileName, stack<char> &text, string cypher)
{
    std::ifstream file(fileName, std::ios::in|std::ios::binary);
    stack<char> temp;
    char ch;

    while (file.get(ch))
        temp.push(ch ^ cypher[temp.size() % cypher.length()]);

    while (!temp.empty())
    {
        text.push(temp.top());
        temp.pop();
    }
}

РЕДАКТИРОВАТЬ: стек требуется. Я собираюсь реализовать свой собственный класс стека, но я пытаюсь заставить это работать сначала с библиотекой стека. Кроме того, если есть лучший способ реализовать это, пожалуйста, дайте мне знать. В противном случае, я считаю, что в этом нет ничего особенного, кроме как заставить его пройти цикл для кодирования и декодирования всего файла. Я просто не уверен, почему он останавливается, скажем, на 20 символов или на 10 символов. Я знаю, что это связано с тем, как долго шифр тоже, поэтому я считаю, что это в% (мод). Просто не уверен, как переписать.

РЕДАКТИРОВАТЬ: Хорошо, попробовал решение WhozCraig, и я не получаю желаемый результат, поэтому ошибка теперь должна быть в моей основной. Вот мой код для основного:

#include <iostream> 
#include <iomanip> 
#include <fstream>
#include <string> 
#include <cstdlib>
#include <cctype>
#include <stack>


using namespace std;

void readFileEncode(string fileName, stack<char> &text, string cypher);

int main()
{
    stack<char> text;   // allows me to use stack from standard library
    string cypher;
    string inputFileName;
    string outputFileName;
    int position;

    cout << "Enter a cypher code" << endl;
    cin >> cypher;
    cout << "Enter the name of the input file" << endl;
    cin >> inputFileName;

    position = inputFileName.find(".iia");//checks to see if the input file has the iia extension

    if (position > 1){
        outputFileName = inputFileName;
        outputFileName.erase(position, position + 3);// if input file has the .iia extension it is erased 
    }
    else
        //outputFileName.erase(position, position + 3);// remove the .txt extension and
        outputFileName = inputFileName + ".iia";// add the .iia extension to file if it does not have it

    cout << "Here is the new name of the inputfile " << outputFileName << endl; // shows you that it did actually put the .iia on or erase it depending on the situation

    system("pause");

    readFileEncode(inputFileName, text, cypher); //calls function            

    std::ofstream file(outputFileName); // calling function

    while (text.size()){// goes through text file
        file << text.top();
        text.pop(); //clears pop
    }

    system("pause");
}

В основном я читаю файл.txt для шифрования и затем добавляю расширение файла.iia к имени файла. Затем я возвращаюсь назад, ввожу файл обратно с расширением.iia, чтобы декодировать его обратно. Когда я расшифровываю его обратно, это примерно бессмысленно после первых десяти слов.

@WhozCraig Имеет ли значение, что в файле есть пробелы, переводы строки или пунктуация? Может быть, с полным решением здесь вы можете указать мне, что не так.

2 ответа

Решение

Если я понимаю, что вы пытаетесь сделать правильно, вы хотите, чтобы весь файл вращался XOR с символами в ключе шифра. Если это так, вы, вероятно, можете устранить свою непосредственную ошибку, просто выполнив следующее:

void readFileEncode(string fileName, stack<char> &text, string cypher)
{
    std::ifstream file(fileName, std::ios::in|std::ios::binary);
    stack<char> temp;
    char ch;

    while (file.get(ch))
        temp.push(ch ^ cypher[temp.size() % cypher.length()]);

    while (!temp.empty())
    {
        text.push(temp.top());
        temp.pop();
    }
}

Наиболее заметные изменения

  • Открытие файла в двоичном режиме с помощью std::ios::in|std::ios::binary для открытого режима. это избавит от необходимости вызывать noskipws манипулятор (обычно это вызов функции) для каждого извлеченного символа.
  • С помощью file.get(ch) извлечь следующий символ. Участник будет извлекать следующий символ из буфера файлов напрямую, если он доступен, в противном случае загрузите следующий буфер и попробуйте снова.

альтернатива

Персональный подход будет дорогостоящим в любом случае. Что это переживает stack<>, который будет поддержан vector или же deque не собирается делать вам какие-либо услуги. То, что он проходит через два из них, только усиливает агонию. Вы также можете загрузить весь файл за один раз, вычислить все XOR напрямую, а затем поместить их в стек через обратный итератор:

void readFileEncode
(
    const std::string& fileName,
    std::stack<char> &text,
    const std::string& cypher
)
{
    std::ifstream file(fileName, std::ios::in|std::ios::binary);

    // retrieve file size
    file.seekg(0, std::ios::end);
    std::istream::pos_type pos = file.tellg();
    file.seekg(0, std::ios::beg);

    // early exit on zero-length file.
    if (pos == 0)
        return;

    // make space for a full read
    std::vector<char> temp;
    temp.resize(static_cast<size_t>(pos));
    file.read(temp.data(), pos);

    size_t c_len = cypher.length();
    for (size_t i=0; i<pos; ++i)
        temp[i] ^= cypher[i % c_len];

    for (auto it=temp.rbegin(); it!=temp.rend(); ++it)
        text.push(*it);
}

Вы все еще получаете свой стек на стороне вызывающей стороны, но я думаю, что вы будете значительно счастливее с производительностью.

Просто для информации: никогда не читайте файл char за char, вам понадобятся часы, чтобы закончить 100Mb. прочитайте по крайней мере 512 байт (в моем случае я прочитал непосредственно 1 или 2Mb ==> store в char * и затем обработал).

Другие вопросы по тегам