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

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

Восстановить пароль Регистрация
 
 
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 15:32     Прочитать бинарник картинки через std::cin #1
Здравствуйте дорогие форумчане!
У меня возникла такая не тривиальная задача, вот собственно в чем фишка:
Нужно написать на С++ программу котрая получит файл из 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
Посмотрите здесь:

Как исправить ошибку с std::cin C++
C++ Не воспринимает ни std::cout, ни std::cin. Вобщем ничего из std. Также не понимает iostream
Из scanf в std::cin C++
C++ std::cin
C++ Не работает std::cout || std::cin
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Nick Alte
Эксперт С++
1590 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,897
Завершенные тесты: 1
03.11.2013, 16:01     Прочитать бинарник картинки через std::cin #2
Для неформатированного ввода существует функция read.
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 17:05  [ТС]     Прочитать бинарник картинки через std::cin #3
Ув. Nick Alte. Спасибо вам большое. Через read все прекрасно читается. Даже немного стыдно что упустил такое простое решение, а то я уже пробовал даже подменить буфер cin-а на свой, пробовал извлекать из буфера cin-a данные напрямую и страдал прочей фигней, а все оказалось до беды просто, спасибо вам еще раз.

Добавлено через 30 минут
К сожалению проблема в силе, read данные то прочитал, но валидными оказалась только та часть которую я и до этого считывал.
Nick Alte
Эксперт С++
1590 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,897
Завершенные тесты: 1
03.11.2013, 17:25     Прочитать бинарник картинки через std::cin #4
Возможно, стоило упомянуть, что читать надо не в string, а в массив, vector<char> или нечто в этом роде.
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 17:32  [ТС]     Прочитать бинарник картинки через std::cin #5
C++
1
2
char *str = new char[size+1];
std::cin.read(str,size);
Об этом не стоило упоминать, я и так догадался
grizlik78
Эксперт С++
 Аватар для grizlik78
1884 / 1416 / 102
Регистрация: 29.05.2011
Сообщений: 2,961
03.11.2013, 18:41     Прочитать бинарник картинки через std::cin #6
ОС, в которой всё это происходит, надеюсь, не Windows? Хотя... Строка 9 намекает, что всё-таки Windows. Боюсь, что там стандартный поток ввода неполноценный.
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 19:09  [ТС]     Прочитать бинарник картинки через std::cin #7
Цитата Сообщение от grizlik78 Посмотреть сообщение
ОС, в которой всё это происходит, надеюсь, не Windows? Хотя... Строка 9 намекает, что всё-таки Windows. Боюсь, что там стандартный поток ввода неполноценный.
ОCь Windows, а не подскажите в чем именно неполноценность потока ввода?
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
03.11.2013, 19:48     Прочитать бинарник картинки через std::cin #8
Цитата Сообщение от grizlik78 Посмотреть сообщение
Боюсь, что там стандартный поток ввода неполноценный.
Что же в нем такого ущербного?
Цитата Сообщение от grizlik78 Посмотреть сообщение
Хотя... Строка 9 намекает, что всё-таки Windows.
Неужели в каком-нибудь Linux локаль не может называться "Russian"?
grizlik78
Эксперт С++
 Аватар для grizlik78
1884 / 1416 / 102
Регистрация: 29.05.2011
Сообщений: 2,961
03.11.2013, 20:49     Прочитать бинарник картинки через std::cin #9
Цитата Сообщение от Maxim Petruck Посмотреть сообщение
ОCь Windows, а не подскажите в чем именно неполноценность потока ввода?
Цитата Сообщение от Tulosba Посмотреть сообщение
Что же в нем такого ущербного?
Ну вот в том и ущербность, что файлы в DOS/Windows зачем-то делятся на текстовые и бинарные, и стандартный поток при этом работает в режиме текстового файла. Не знаю, есть ли какие способы это изменить.
Цитата Сообщение от Tulosba Посмотреть сообщение
Неужели в каком-нибудь Linux локаль не может называться "Russian"?
Ну, чисто технически, наверное, может. Хотя так не принято. Поэтому и говорю, что намекает. Я же не был уверен на 100%.
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
03.11.2013, 21:01     Прочитать бинарник картинки через std::cin #10
Цитата Сообщение от grizlik78 Посмотреть сообщение
что файлы в DOS/Windows зачем-то делятся на текстовые и бинарные
Файлы все бинарные, другое дело - режим открытия этих файлов.
Цитата Сообщение от grizlik78 Посмотреть сообщение
и стандартный поток при этом работает в режиме текстового файла.
Вы бы лучше примерчик привели для прояснения, чтобы было видно разницу Win/не-Win.
grizlik78
Эксперт С++
 Аватар для grizlik78
1884 / 1416 / 102
Регистрация: 29.05.2011
Сообщений: 2,961
03.11.2013, 21:28     Прочитать бинарник картинки через std::cin #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  [ТС]     Прочитать бинарник картинки через std::cin #12
Цитата Сообщение от grizlik78 Посмотреть сообщение
Если известен способ, как переоткрыть стандартный поток ввода в бинарный режим (но не из файла, так как данные и по конвейеру могут передаваться), то именно это и нужно автору.
А что если поробовать создать свой поток ввода изначально его создать в бинарном режиме и через аргументы командной сделать чтобы весь вывод шел туда, такое ведь в принципе возможно?
grizlik78
Эксперт С++
 Аватар для grizlik78
1884 / 1416 / 102
Регистрация: 29.05.2011
Сообщений: 2,961
03.11.2013, 21:36     Прочитать бинарник картинки через std::cin #13
Maxim Petruck, а что, временные файлы вообще не вариант? Почему нужен именно стандартный ввод?
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 21:38  [ТС]     Прочитать бинарник картинки через std::cin #14
Фишка в том, что данные я принимаю с HTML формы методом POST, а в этом случае все идет в стандартные потоки ввода.
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
03.11.2013, 21:47     Прочитать бинарник картинки через std::cin #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 секунды
ну ты его получил в стандартный поток, а что будешь с ним делать дальше, он там в виде строки храниться и я думаю обычной.
grizlik78
Эксперт С++
 Аватар для grizlik78
1884 / 1416 / 102
Регистрация: 29.05.2011
Сообщений: 2,961
03.11.2013, 21:51     Прочитать бинарник картинки через std::cin #16
Ну, на самом деле есть способ. Вот так мой пример будет работать нормально с любыми файлами:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <fstream>
#include <fcntl.h>
 
int main()
{
    _setmode(_fileno(stdin), _O_BINARY);
    std::ofstream out("result.dat", std::ios::binary);
    int c;
    while ( (c = std::cin.get()) !=EOF)
        out.put(c);
    return 0;
}
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
03.11.2013, 22:01     Прочитать бинарник картинки через std::cin #17
отут от:
C++
1
2
char *str = new char[size+1];
std::cin.read(str,size);
Попробуй заменить size на 900000, мб будет работать без ошибок.
Это если ты говоришь у тебя бинарная строка в cin, то при встрече 0 она оборвется и возможно реальный размер ее ты не увидешь.

Добавлено через 2 минуты
Ладно экспериментируй, ну ты явно напутал там что то с размером буфера, если с ошибками сохраняет.
Maxim Petruck
0 / 0 / 0
Регистрация: 03.11.2013
Сообщений: 12
03.11.2013, 22:07  [ТС]     Прочитать бинарник картинки через std::cin #18
Цитата Сообщение от ninja2 Посмотреть сообщение
Автору наверно нужно сначала сохранить файл на диск в бинарном режиме
К сожалению нельзя, нужно его именно напрямик переработать, без лишних "телодвижений".

Цитата Сообщение от ninja2 Посмотреть сообщение
А что ты думаешь делать с изображением дальше?
Мне нужно изображение где-то в памяти разместить не важно в каком виде, а потом я его возьму и перекодирую в строку.

Цитата Сообщение от ninja2 Посмотреть сообщение
Затем считай его в бинарном режиме и сможешь вычислить реальный размер который изображение будет занимать
Мне даже так известен размер входных данных, я ориентируясь на них и так пытаюсь считывать данные.
Мне кажется что из-за текстового режима передачи данных они приходят не до конца. Я просто пробовал проходить по streambuf-у cin-a и это всё-равно ничего не дало.
grizlik78
Эксперт С++
 Аватар для grizlik78
1884 / 1416 / 102
Регистрация: 29.05.2011
Сообщений: 2,961
03.11.2013, 22:09     Прочитать бинарник картинки через std::cin #19
Цитата Сообщение от Maxim Petruck Посмотреть сообщение
Мне кажется что из-за текстового режима передачи данных они приходят не до конца.
Скорее всего так и есть. Что ж, пробуй _setmode().
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.11.2013, 22:10     Прочитать бинарник картинки через std::cin
Еще ссылки по теме:

Локаль в std::cin.getline (вижуал с++) C++
Std::cin, символ новой строки C++
C++ Как выполнять std::cin в LOOP ?

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

Или воспользуйтесь поиском по форуму:
ninja2
 Аватар для ninja2
230 / 186 / 7
Регистрация: 26.09.2012
Сообщений: 2,018
Завершенные тесты: 1
03.11.2013, 22:10     Прочитать бинарник картинки через std::cin #20
Цитата Сообщение от Maxim Petruck Посмотреть сообщение
Мне даже так известен размер входных данных, я ориентируясь на них и так пытаюсь считывать данные.
ну так в чом проблема read(file, size); и все должно работать.
Yandex
Объявления
03.11.2013, 22:10     Прочитать бинарник картинки через std::cin
Ответ Создать тему
Опции темы

Текущее время: 15:12. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru