Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
#1

Прочитать бинарник картинки через std::cin - C++

03.11.2013, 15:32. Просмотров 870. Ответов 22
Метки нет (Все метки)

Здравствуйте дорогие форумчане!
У меня возникла такая не тривиальная задача, вот собственно в чем фишка:
Нужно написать на С++ программу котрая получит файл из html формы(в данном случае это картинка) и мне в стандартный поток ввода приходит бинарное содержимое этой картинки.
Если кому интересно зачем я это делаю

Изначально задача состоит в том, чтобы получить картинку через html форму в С++ программе перекодировать в формат BASE64. И вывести ее на веб сранице как картинку, через уже известную нам строку BASE64.
С тем чтобы перекодировать буфер данных в BASE64 у меня проблем не возникло, но вот читать такие данные через стандартные потоки ввода доставило мне не мало проблем.

Проблема возникла в том, что при чтении бинарника картинки все данные считать не удается. Я читать это все уже пробовал кучей способов, лучший результат был когда я считал 1 кб из 5 кб. Когда читаю не картинку, а текстовый файл все работает четко читаю и по 5 мб без проблем.
Моё предположение, что из-за формата картинки при чтении данных встречается последовательность битов которая означает конец входных данных. Еще возможно из-за очень большой длинны строки, она переваливает за 1 кб она как-то урезается, но тогда она должна была бы по идее переносться на следующую строку, чего на деле не происходит.

Если вы знаете как возможно прочитать эти все данные через стандартные потоки ввода или как можно подменить потоки ввода чтобы это все читалось, вообщем если есть любые идеи, буду рад вас послушать.

Код прилагаю. Знаю что все это костыльно смотрится, но марафет буду наводить потом, когда справлюсь с сзадачей.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <string>
#include <stdlib.h>
#include <locale.h>
 
int main(int argc, char* argv[], char* env[])
{
    setlocale(LC_ALL, "Russian"); 
    std::string tmp;
    int size = atoi(getenv("CONTENT_LENGTH")); // Размер получаемых данных
    //Здесь я отрезаю не нужную мне информацию 
    std::getline(std::cin,tmp);
    size -= tmp.size()+1;
    std::getline(std::cin,tmp);
    size -= tmp.size()+1;
    std::getline(std::cin,tmp,':');
    size -= tmp.size()+1;
    std::string type;
    std::getline(std::cin,type);
    size -= type.size()+1;
    std::getline(std::cin,tmp);
    size -= tmp.size()+1;
    std::string str;
    str.reserve(size);
    
    int last; // здесь Я запоминаю размер последней строки, т.к. там в конце еще будет строка разделяющая данные html форм
    // А вот зесь начинается самое интересное, тут то и нужно прочесть бинарник
    // Здесь я уже 2 дня танцую с бубном 
    while(str.size() < size)
    {
        std::getline(std::cin,tmp);
        str += tmp + '\n';
        last += tmp.size()+2; // здесь + 2 чтобы убарть \n с прошлой строки
    }
 
    for(int i = 0; i < last; i++)
        str.pop_back();
 
    std::cout << "Content-type: text/html\n\n";
    std::cout << "<!DOCTYPE html>\n";
    std::cout << "<html>\n";
    std::cout << "<head>\n";
    std::cout << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\">\n";
    std::cout << "<title>Base64</title>\n";
    std::cout << "</head>\n";
    std::cout << "<body>\n";
    std::cout << str;
    std::cout << "Размер файла: " << str.size() << " байт<br>\n";
    std::cout << "</body>\n";
    std::cout << "</html>\n";
    return 0;
}

P.S: Прошу не предлагать использовать никаких сервисов для перекодировки в BASE64. Нужно именно то, что я пытаюсь сделать.

P.P.S: Знаю что С++ система ввода здесь будет работать медленне чем Си-шные scanf(), printf(), особенно на больших данных и знаю что это даже очень заметно замедляет программу, но сейчас это мне не важно.
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.11.2013, 15:32
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Прочитать бинарник картинки через std::cin (C++):

Не воспринимает ни std::cout, ни std::cin. Вобщем ничего из std. Также не понимает iostream - C++
Здравствуйте! Я хотел начать изучать язык C++. Набрал литературы. Установил Microsoft Visual C++ 2005 Express Edition. Образ диска...

Не работает std::cout || std::cin - C++
#include &quot;Account.h&quot; #include &lt;string&gt; #include &lt;iostream&gt; using std::cout; Account :: Account(int startBalance) { ...

std::cin - C++
const int MAX = 256; int main() { char buf; std::cout&lt;&lt;(std::cin&gt;&gt;buf); return 0; } Я в консоли вижу странный вывод...

Из scanf в std::cin - C++
Как тоже самое сделать с помощью std::cin? printf(&quot;Введите автора %d книги.\n&quot;,i+1); scanf(&quot;%31s &quot;,ar.author); ...

Очистка (блокировка) std::cin - C++
Здравствуйте. Такой вопрос. Программа отрисовывает в консоль поле раз в n секунд несколько раз подряд (что-то типа анимации). В течение...

Как исправить ошибку с std::cin - C++
помогите у меня пропускает последующие вводы если вводишь знак или букву вот код std::cout&lt;&lt;&quot;A: &quot;; std::cin&gt;&gt;AA; ...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Nick Alte
Эксперт С++
1636 / 1008 / 119
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
03.11.2013, 16:01 #2
Для неформатированного ввода существует функция read.
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 17:05  [ТС] #3
Ув. Nick Alte. Спасибо вам большое. Через read все прекрасно читается. Даже немного стыдно что упустил такое простое решение, а то я уже пробовал даже подменить буфер cin-а на свой, пробовал извлекать из буфера cin-a данные напрямую и страдал прочей фигней, а все оказалось до беды просто, спасибо вам еще раз.

Добавлено через 30 минут
К сожалению проблема в силе, read данные то прочитал, но валидными оказалась только та часть которую я и до этого считывал.
Nick Alte
Эксперт С++
1636 / 1008 / 119
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
03.11.2013, 17:25 #4
Возможно, стоило упомянуть, что читать надо не в string, а в массив, vector<char> или нечто в этом роде.
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 17:32  [ТС] #5
C++
1
2
char *str = new char[size+1];
std::cin.read(str,size);
Об этом не стоило упоминать, я и так догадался
grizlik78
Эксперт С++
1908 / 1440 / 111
Регистрация: 29.05.2011
Сообщений: 2,996
03.11.2013, 18:41 #6
ОС, в которой всё это происходит, надеюсь, не Windows? Хотя... Строка 9 намекает, что всё-таки Windows. Боюсь, что там стандартный поток ввода неполноценный.
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 19:09  [ТС] #7
Цитата Сообщение от grizlik78 Посмотреть сообщение
ОС, в которой всё это происходит, надеюсь, не Windows? Хотя... Строка 9 намекает, что всё-таки Windows. Боюсь, что там стандартный поток ввода неполноценный.
ОCь Windows, а не подскажите в чем именно неполноценность потока ввода?
Tulosba
:)
Эксперт С++
4393 / 3236 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
03.11.2013, 19:48 #8
Цитата Сообщение от grizlik78 Посмотреть сообщение
Боюсь, что там стандартный поток ввода неполноценный.
Что же в нем такого ущербного?
Цитата Сообщение от grizlik78 Посмотреть сообщение
Хотя... Строка 9 намекает, что всё-таки Windows.
Неужели в каком-нибудь Linux локаль не может называться "Russian"?
grizlik78
Эксперт С++
1908 / 1440 / 111
Регистрация: 29.05.2011
Сообщений: 2,996
03.11.2013, 20:49 #9
Цитата Сообщение от Maxim Petruck Посмотреть сообщение
ОCь Windows, а не подскажите в чем именно неполноценность потока ввода?
Цитата Сообщение от Tulosba Посмотреть сообщение
Что же в нем такого ущербного?
Ну вот в том и ущербность, что файлы в DOS/Windows зачем-то делятся на текстовые и бинарные, и стандартный поток при этом работает в режиме текстового файла. Не знаю, есть ли какие способы это изменить.
Цитата Сообщение от Tulosba Посмотреть сообщение
Неужели в каком-нибудь Linux локаль не может называться "Russian"?
Ну, чисто технически, наверное, может. Хотя так не принято. Поэтому и говорю, что намекает. Я же не был уверен на 100%.
Tulosba
:)
Эксперт С++
4393 / 3236 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
03.11.2013, 21:01 #10
Цитата Сообщение от grizlik78 Посмотреть сообщение
что файлы в DOS/Windows зачем-то делятся на текстовые и бинарные
Файлы все бинарные, другое дело - режим открытия этих файлов.
Цитата Сообщение от grizlik78 Посмотреть сообщение
и стандартный поток при этом работает в режиме текстового файла.
Вы бы лучше примерчик привели для прояснения, чтобы было видно разницу Win/не-Win.
grizlik78
Эксперт С++
1908 / 1440 / 111
Регистрация: 29.05.2011
Сообщений: 2,996
03.11.2013, 21:28 #11
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от Tulosba Посмотреть сообщение
Вы бы лучше примерчик привели для прояснения, чтобы было видно разницу Win/не-Win.
Автор темы уже привёл пример.
Ну вот минимальный код.
C++
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <fstream>
 
int main()
{
    std::ofstream out("result.dat", std::ios::binary);
    int c;
    while ( (c = std::cin.get()) !=EOF)
        out.put(c);
    return 0;
}
Если в Windows запустить его как
Код
program.exe < somefile.dat
то во-первых в файле result.dat преобразуются некоторые переводы строки, а во-вторых чтение входного файа прекратится как только в нём встретится байт с кодом 0x1A (Ctrl-Z), который рассматривается как конец текстового потока. Собственно, это наследие CP/M, где такое поведение было необходимо.
В Linux файл result.dat будет в точности соответствовать исходному.
Цитата Сообщение от Tulosba Посмотреть сообщение
Файлы все бинарные, другое дело - режим открытия этих файлов.
Это понятно. Непонятно зачем в DOS принято, что стандартный поток должен быть исключительно текстовым.

Добавлено через 3 минуты
Если известен способ, как переоткрыть стандартный поток ввода в бинарный режим (но не из файла, так как данные и по конвейеру могут передаваться), то именно это и нужно автору.
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 21:35  [ТС] #12
Цитата Сообщение от grizlik78 Посмотреть сообщение
Если известен способ, как переоткрыть стандартный поток ввода в бинарный режим (но не из файла, так как данные и по конвейеру могут передаваться), то именно это и нужно автору.
А что если поробовать создать свой поток ввода изначально его создать в бинарном режиме и через аргументы командной сделать чтобы весь вывод шел туда, такое ведь в принципе возможно?
grizlik78
Эксперт С++
1908 / 1440 / 111
Регистрация: 29.05.2011
Сообщений: 2,996
03.11.2013, 21:36 #13
Maxim Petruck, а что, временные файлы вообще не вариант? Почему нужен именно стандартный ввод?
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 21:38  [ТС] #14
Фишка в том, что данные я принимаю с HTML формы методом POST, а в этом случае все идет в стандартные потоки ввода.
ninja2
231 / 187 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
03.11.2013, 21:47 #15
Цитата Сообщение от grizlik78 Посмотреть сообщение
Если известен способ, как переоткрыть стандартный поток ввода в бинарный режим (но не из файла, так как данные и по конвейеру могут передаваться), то именно это и нужно автору.
Можно только файловый поток открыть в бинарном режиме. Автору наверно нужно сначала сохранить файл на диск в бинарном режиме, просто буфер задать большого размера например что то вроде этого ifs.write(img,3000000), на диск запишеться только тот размер который имеет реально изображение. У меня была проблема при считывании изображения с интернета, оно передается в виде страки и если просто записать ifs <<img, то не весь файл записывается и при просмотре некоторые изображения были повреждены, а когда я от фанаря взял буфер поставил громадное число, то все заработало как нужно и ни одного поврежденного изображения.

ТС попробуй при чтении или записи буфер изменить от фанаря большой поставить, там например 90000000 такой поставь, мб ошибок не будет!. Если будет ошибка и запросит реальный буфер, то тогда просто сохрани файл на диск с помощью файлового потока (бинарный режим) write(img,9000000); тут не будет 100% ошибки буфер можно любой ставить, запишеться скоко в реале. Затем считай его в бинарном режиме и сможешь вычислить реальный размер который изображение будет занимать в бинарном режиме ну там через указатели на начало и конец потока (функции не помню), а хотя это не поможет, ту ж его хочешь в cin загнать, а из cin куда оно у тебя попадет?
Цитата Сообщение от Maxim Petruck Посмотреть сообщение
Нужно написать на С++ программу котрая получит файл из html формы(в данном случае это картинка) и мне в стандартный поток ввода приходит бинарное содержимое этой картинки.
Ага походу тебе бинарное содержимое никогда не придет, тебе придет только строка. Просто сохрани ее на диск с помощью файловых потоков, которые можно открыть в бинарном режиме указав размер буфера с запасом, тогда картинки не будут повреждаться write(img,9999999999);
Если у тебя ошибки то ты возможно размер буфера не правильно указываешь, при бинарной записи он разрастется в разы.

Добавлено через 41 секунду
Цитата Сообщение от Maxim Petruck Посмотреть сообщение
Фишка в том, что данные я принимаю с HTML формы методом POST, а в этом случае все идет в стандартные потоки ввода.
А что ты думаешь делать с изображением дальше?

Добавлено через 52 секунды
ну ты его получил в стандартный поток, а что будешь с ним делать дальше, он там в виде строки храниться и я думаю обычной.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.11.2013, 21:47
Привет! Вот еще темы с ответами:

std::cin & switch case - C++
Всем привет. Вообщем проблема такая: while(val) { int choice; std::cin &gt;&gt; choice; switch(choice) { case 1: ...

Локаль в std::cin.getline (вижуал с++) - C++
собственно выводит в консоль нормально, а вот после считывания с консоли в символьный массив попадают крокозябры: #include &quot;stdafx.h&quot; ...

Как выполнять std::cin в LOOP ? - C++
Хочу сделать что то вроде командной строки. 1ый раз читает и выполняет нормально, но следующий раз вижу что ждет от меня ввода, но ни...

std::cin Debug Access failed - C++
Решил начать программировать в visual studio 2012 и сразу наткнулся на какую-то непонятную ошибку вот код: #include &quot;stdafx.h&quot; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
03.11.2013, 21:47
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru