Шифратор\дешифратор

Здравствуйте! Захотелось мне как то написать программу, шифрующую файлы. Пишу код:

#include <iostream>
#include <conio.h>
#include <fstream>

using namespace std;

inline unsigned char uncode ( char );

int main(int argc, char** argv)
{
    setlocale ( 0, "Russian" );
    ifstream filein;
    fstream fileout;
    cout << "Здравствуйте! Это программа простейшей шифровки." << endl;
    char inputFname[256], outputFname[256];
    cout << "Сначала введите\
    имя входного файла(не больше 256 символов): " << endl;
    cin.get( inputFname, 256 ); cin.ignore();
    cout << "А также имя выходного файла: " << endl;    
    cin.get( outputFname, 256 ); cin.ignore();
    filein.open ( inputFname, ios::in | ios::binary );
    fileout.open ( outputFname, ios::in | ios::out | ios::trunc | ios::binary );
    if ( filein.is_open() )
    {
        cout << "Файл " << inputFname << " успешно открыт!"<< endl;
        if ( fileout.is_open() )
        {
            cout << "Файл " << outputFname << " успешно открыт!"<< endl;    
            unsigned char chr = 0;
            cout << "Пожалуйста, подождите, идёт расшифровка\\шифровка ( разницы никакой )." << endl;
            while ( !filein.eof() )
            {
                filein.read ( ( char* )&chr, sizeof ( char ) );
                chr = uncode ( chr );
                fileout.write ( ( char* )&chr, sizeof ( char ) );
            }
            cout << "Процесс завершён!" << endl;
        }
        else
        {
            cout << "Не удалось открыть выходной файл " << outputFname << " !" << endl;
        }
    }
    else
    {
        cout << "Не удалось открыть входной файл" << inputFname <<" !" << endl;
    }
    cout << "Всё.Нажмите любую клавишу." << endl;
    getch();
    return 0;
}

inline unsigned char uncode ( char chr )
{
    return (~chr);
}

программа компилируется и запускается нормально. Но вот работает не очень. В выходном файле всегда в конец добавляется «x», что, минимум, нежелательно.
Пытался исправить такой конструкцией:

fileout.seekp ( 0, ios::end );
chr = 0;
fileout.write (  ( char* )&chr, sizeof ( char ) );

но теперь в конец добавляется ещё и «я». Есть у вас какие-нибудь мысли по поводу этой ошибки?

P.S.: Вопрос в догонку, раз у создал тему на форуме. Каким образом получается совмещать флаги с помощью | при задании режимов открытия фалов( то же самое у функции MessageBox из Win32Api )?

Что бы избавиться от бага, основной цикл твоей программы может выглядеть так:

            while ( !filein.eof() )
            {
                filein.read ( ( char* )&chr, sizeof ( char ) );
                if ( !filein.eof() ) {
                    chr = uncode ( chr );
                    fileout.write ( ( char* )&chr, sizeof ( char ) );
                }
            }

...или так:

            while ( !filein.eof() )
            {
                filein.read ( ( char* )&chr, sizeof ( char ) );
                if ( filein.gcount() == 1 ) {
                    chr = uncode ( chr );
                    fileout.write ( ( char* )&chr, sizeof ( char ) );
                }
            }

...но лучше всего так:

            while ( filein.read ( ( char* )&chr, sizeof ( char ) ) )
            {
                chr = uncode ( chr );
                fileout.write ( ( char* )&chr, sizeof ( char ) );
            }

Дело в том, что метод eof() не проверяет файл на окончание, а просто констатирует факт, что конец файла уже достигнут. А само обнаружение конца файла происходит при операции чтения, т.е. при вызове метода read(). Поэтому последний считанный символ, при чтении которого установился флаг конца файла, надо обрабатывать как символ конца файла (в данном случае его надо игнорировать).

В последнем варианте кода используется тот факт, что метод read() возвращает this*, т.е. сам поток. А поток в контексте логического выражения преобразуется в true, если с потоком всё в порядке, и в false** в противном случае (в т.ч. и при EOF). Следовательно при достижении конца файла, считанный символ уже не попадёт в тело цикла.

Чисто технически не понравились два момента. Первый:

    fileout.open ( outputFname, ios::in | ios::out | ios::trunc | ios::binary );

для выходного файла флаг ios::in явно лишний.

Второй:

    filein.read ( ( char* )&chr, sizeof ( char ) );

Я бы всё-таки обозначил размер буфера через именованную константу. Вдруг потом захочется читать не по одному символу?

В логике программы не понравилась организация открытия/закрытия файлов. Например, если входной файл не существует, то всё равно будет запрошено имя выходного файла и, мало того, выходной файл будет создан. Пусть и нулевой длины. Попробуй сам исправить логику работы программы.

Оператор | — это оператор побитового ИЛИ. Читай в книжке про битовые операции. Короткое описание есть в Википедии.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.