Как читать текстовый файл по 3 символа за раз?

Я учусь программировать на C, и сейчас моя домашняя работа такая. Я должен иметь возможность взять текстовый файл со словами/буквами, и моя программа должна печатать коды ascii + 1 букв, которые она получает. Это «кодирование». Так, например, буква «А» будет напечатана как 066. Итак, моя проблема в том, что программа должна также иметь возможность декодировать эти коды ascii обратно в буквы, но я не знаю, как заставить мою программу читать 3 числа в однажды. я использовал

c = fgetc(pF);  
while (c != EOF) {  
fprintf(pF2,"%03i",c+1); 
c = fgetc(pF);  

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

#include "stdio.h"
#include "stdlib.h"

int encode(){
char * fName = "testR.txt";
char * fName2="testW.txt";
FILE * pF;
FILE * pF2;
char c, cArray[500];
int i=0;

pF = fopen(fName, "r");
if ( pF == NULL ) {
    printf("Error: The specified file could not be opened.\n");
    return -1;
}
pF2 = fopen(fName2, "w");

c = fgetc(pF);
while (c != EOF) {
fprintf(pF2,"%03i",c+1);
    c = fgetc(pF);
}
fclose(pF); 
fclose(pF2);
return;
}

char decode(){
char * fName = "testW.txt";
char * fName2="testW2.txt";
char * buf;
FILE * pF;
FILE * pF2;
char  cArray[500];
char buffer[4];
     buffer[3] = '\0';

pF = fopen(fName, "r");
if ( pF == NULL ) {
    printf("Error: The specified file could not be opened.\n");
    return -1;
}
pF2 = fopen(fName2, "w");
while (fread(buffer, 3, 1, stdin)){
putchar((atoi(buffer)-1) & 0xFF);
}
fclose(pF); 
fclose(pF2);
}

int main (int argc, char *argv[]){
char c;

if ( argc != 2 ) { 
  printf("Incorrect number of arguments.\n"); 
  exit(-1); 
} 

if (strcmp(argv[1], "-e") == 0){
   encode();
   }
if (strcmp(argv[1], "-d") == 0){
   decode();
   }
return 0;
}

Я знаю, что мой код беспорядок, и, вероятно, есть вещи, которые не должны быть там из-за всех изменений, которые я пытался сделать =[


person JustAGuy    schedule 30.11.2013    source источник
comment
fread(buf, 1, 3, pF);   -  person bvj    schedule 30.11.2013
comment
буду ли я по-прежнему использовать (c != EOF)?   -  person JustAGuy    schedule 30.11.2013
comment
нет. Сначала объявите buf, а затем используйте fread. thes читает 3 символа из pF и сохраняет их в buf.   -  person fastr.de    schedule 30.11.2013
comment
Функция возвращает количество прочитанных элементов относительно третьего аргумента count. Обычно возникает ошибка, когда возвращаемое значение и количество не совпадают.   -  person bvj    schedule 30.11.2013
comment
Хорошо, я думаю, что у меня это есть, но как мне сделать так, чтобы он читал весь файл?   -  person JustAGuy    schedule 30.11.2013
comment
В какой кодировке текстовый файл? Если это простой ASCII, вы читаете один байт, и единственная проблема заключается в форматировании. Если это не ASCII, вам нужно сделать что-то другое. Читать слова/буквы из текстового файла бессмысленно, если мы (и вы) ничего не знаем о кодировке.   -  person Ken White    schedule 30.11.2013


Ответы (2)


Кодировка:

int c;

while ((c = getchar()) != EOF)
    printf("%.3d", (c+1)&0xFF);

Расшифровка:

char buffer[4];
buffer[3] = '\0';

while (fread(buffer, 3, 1, stdin))
    putchar((atoi(buffer)-1) & 0xFF);

Технически, если вывод не заканчивается новой строкой при кодировании, вывод не является текстовым файлом. На входе нет проверки ошибок. fread() вернет 1 при чтении тройки символов; в противном случае он вернет 0.

Рабочие программы

e3.c — шифрование

#include <stdio.h>

int main(void)
{
    int c;

    while ((c = getchar()) != EOF)
        printf("%.3d", (c+1)&0xFF);
    return 0;
}

d3.c — расшифровка

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char buffer[4];
    buffer[3] = '\0';

    while (fread(buffer, 3, 1, stdin))
        putchar((atoi(buffer)-1) & 0xFF);
    return 0;
}

Пример вывода

$ e3 < e3.c
036106111100109118101102033061116117101106112047105063011011106111117033110098106111041119112106101042011124011033033033033106111117033100060011011033033033033120105106109102033041041100033062033104102117100105098115041042042033034062033070080071042011033033033033033033033033113115106111117103041035038047052101035045033041100044050042039049121071071042060011033033033033115102117118115111033049060011126011011$
$

Доллар в конце строки — это подсказка.

$ e3 <e3.c | d3
#include <stdio.h>

int main(void)
{
    int c;

    while ((c = getchar()) != EOF)
        printf("%.3d", (c+1)&0xFF);
    return 0;
}

$ e3 <e3.c | d3 | diff e3.c -
$

Базовый цикл кодирования и декодирования показывает, что код работает.

person Jonathan Leffler    schedule 30.11.2013
comment
Да, это первая часть программы. Он уже делает это. Теперь я пытаюсь создать в своей программе еще одну функцию, которая заменяет «066» обратно на A, а затем записывает A в новый документ, зацикливая это до тех пор, пока в основном я не получу исходный документ. - person JustAGuy; 30.11.2013
comment
Это часть «кодирования»; учитывая A, он выведет 066. Декодирование считывает три символа в буфер с завершающим нулем, затем применяет atoi(), чтобы получить 66, вычитает 1, чтобы получить обратно 65, которые он выводит как символ. - person Jonathan Leffler; 30.11.2013
comment
@JonathanLeffler Точно. Эта вторая часть доставляет мне неприятности. - person JustAGuy; 30.11.2013
comment
+1. Я исправляюсь. Рад, что я не DV. :-) Удаляю свой комментарий, чтобы убрать беспорядок. - person Ken White; 30.11.2013

person    schedule
comment
Это совершенно неправильно, если файл представляет собой простой текст ASCII; чтение одного символа требует чтения одного байта, а не трех. - person Ken White; 30.11.2013
comment
Понял, чувствую себя глупо. Итак, теперь программа создает файл, который я пытаюсь создать, но в нем ничего нет, и программа на самом деле не завершается должным образом. Сохраняются ли три читаемых символа в buf, или, если нет, я могу получить к ним доступ? Потому что мне нужно преобразовать их из кодов ascii обратно в символы. - person JustAGuy; 30.11.2013
comment
Три символа, считанные из файла, хранятся в buf, который должен быть определен как массив символов (например, char buf[3]). Таким образом, в вашем примере, если ваш входной файл содержит символы 066, то после вызова fread buf[0] будет содержать символ 0, buf[1] будет содержать символ 6, а buf[2] будет содержать символ 6. - person Tim Pierce; 30.11.2013
comment
@KenWhite, насколько я понимаю, оператор кодирует значение символа в виде трехзначной строки в файл; т. е. %03i. Это, конечно, потребует чтения 3 символов. Завершение строки не кажется проблемой, поэтому двоичный/текстовый код пока не имеет значения. - person bvj; 30.11.2013
comment
Предполагая, что это совместимо с любой кодировкой входного файла OP, единственной серьезной проблемой является порядок параметров размера/количества до fread. Если это действительно так, как описано, считываемый элемент содержит ровно три символа, и поэтому частичное чтение является условием отказа. Следовательно, это должно читаться как while (fread(buf, 3, 1, pF) == 1). Все это при условии, что это формат, который хочет OP (в чем я искренне сомневаюсь, поскольку он не учитывает пробелы, разделители строк и т. Д., Не зная формата файла, невозможно точно ответить). - person WhozCraig; 30.11.2013
comment
@bvj: Откуда вы это взяли, возьмите текстовый файл со словами / буквами, и моя программа должна печатать коды ascii + 1 букв, которые она получает? В нем говорится о кодировании вывода, а не о чтении из закодированного файла, и речь идет о чтении «буквы A», а не трех символов «065». Текстовый файл со словом и буквами можно создать с помощью copy con из командной строки. - person Ken White; 30.11.2013
comment
Формат файла, который я считаю, представляет собой обычный текст (это файл .txt), и в файле, из которого я рисую, нет пробелов или разделителей строк. - person JustAGuy; 30.11.2013
comment
@WhozCraig запись представляет собой последовательный поток элементов sizeof(char), а не 3-байтовых фрагментов данных. Ваша точка зрения, безусловно, актуальна при записи двоичных данных через fwrite с учетом проблем порядка байтов. - person bvj; 30.11.2013
comment
Видимо, я недостаточно ясно выразился, извините, если отнимаю у ваших ребят время. Программа имеет 2 переключателя командной строки. Первый - это -e, который возьмет текстовый документ и создаст новый документ, заменяя каждый символ числом. Второй ключ -d, который должен принимать 3 ЦИФРЫ и превращать их обратно в буквы. - person JustAGuy; 30.11.2013
comment
@user2985744 user2985744 вы так и не прояснили здесь гамбит. Являются ли 3 ЦИФРЫ на самом деле символьными цифрами ?? если да, то большая часть этого актуальна (и я верю, что так и есть). - person WhozCraig; 30.11.2013
comment
Проблемы @bvj endianess не имеют ничего общего с моим комментарием. мой комментарий касается потребления данных из потока. fread(buf,1,3,pF) может с успехом потреблять до трех символов из входного потока, а условие отказа ( == 3) логично, но недочитанные данные теряются (т.е. если было только 2 символа, они сейчас находятся в buf но вы этого не знаете, потому что все, что вы знаете, это то, что 3 не читались). Использование fread(buf,3,1,pF) гарантирует, что вы либо получите их все, либо ничего не прочитаете, и не потеряете ни одного недочитанного. это был мой единственный пункт. - person WhozCraig; 30.11.2013
comment
@bvj: ОП перевернул вопрос три раза (сначала неясно, затем в комментарии к вашему сообщению в виде простого текста, а затем в комментарии к ответу Джонатана он отличается на основе переключателя командной строки, и код делает и то, и другое это актуально, потому что это действительно не обычный текстовый файл, и его действительно нужно вернуть к обычному текстовому файлу, которым он был раньше). - person Ken White; 30.11.2013
comment
@KenWhite Первоначально я опубликовал первый комментарий, но расширил его до ответа, учитывая любопытство оператора прочитать весь исходный файл. Я не собирался привлекать к себе столько внимания :) - person bvj; 30.11.2013