ページ 1 / 1
std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 17:48
by chibago
皆様、お久しぶりです。chibagoです。
今回、御教授いただきたいのはstd::ostringstreamに取り込んだバイナリデータのhex表示に
関してのものです。
現在、boostのシリアライズ機能を利用して、バイナリにシリアライズしたデータを
sqliteのバイナリ形式(blob)としてデータベースに取り込みたいと思っております。
大体の所まではいっているのですが、もうちょっとのところでつまづいております。
流れとしては
コード:
std::ostringstream os;
boost::archive::binary_oarchive bo(os);
bo << (const mydata<float>&) info;
std::string query = "insert into my_table(mydata) values( ? );";
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, query.c_str(),
-1, &statement, 0) == SQLITE_OK){
int rc = 0;
rc = sqlite3_bind_blob(statement, 1, os.str().c_str(), os.str().length(),
NULL);
これは、シリアライズ単体の部分と、bind_blobを通してstd:stringを受け渡し(hello world等の文字列で)は
それぞれ動作を確認しておりますが、バイナリデータをc_str()で吐き出すときにC_strで表現できない
部分が無くなっているようです。(標準出力にstringのままとc_strで出した場合とでの表示が異なります。)
これを回避する方法としてバイナリデータをHeX表示で受け渡しすることを考えております。(もともと、sqliteの
バイナリはhexでやりとりするのが普通のようです。)
c_strにHeXで吐き出す方法はございますでしょうか。
ご教授いただければ幸いです。
また、他の解決法がございましたらそちらも歓迎致します。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 18:29
by h2so5
c_str()はCの文字列として出力するので、途中にNULLがあるとそこまでしか出力されません。
バイナリデータをそのまま取り出すには data() を使います。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 18:54
by かずま
sqlite3_prepare_v2 の第3引数のバイト数が負だと、
query.c_str() の途中の '\0' の前までの長さと解釈されます。
-1 を query.size() または query.length() に変えてみてください。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 19:10
by かずま
かずま さんが書きました:sqlite3_prepare_v2 の第3引数のバイト数が負だと、
query.c_str() の途中の '\0' の前までの長さと解釈されます。
とんでもない勘違いでした。query は上で定義されていて '\0' なんか途中にありませんね。
query ではなく、os.str() の問題ですね。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 19:45
by かずま
愚直ですが、これでどうでしょうか?
コード:
#include <iomanip>
std::ostringstream os2;
os2 << std::hex << std::setfill('0');
for (size_t i = 0; i < os.str().length(); i++)
os2 << std::setw(2) << (os.str().c_str()[i] & 0xff);
rc = sqlite3_bind_blob(statement, 1, os2.str().c_str(),
os2.str().length(), NULL);
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 20:22
by chibago
かずま様、h2so5様、
お返事ありがとうございます。
data()の件は試しましたがダメでした。
std::coutで見る限り(これがダメかもしれませんが)はc_str()と同様の
動作に思えます。
かずま様にはコーディングまで示していただきありがとうございます。
自分で16進数と言い出してあつかいをあまりしりませんでした。
今度は受け手側でこまっております。
select文でバイナリデータを取り出しistringstrea経由で
デシリアライズを試みております。
コード:
std::istringstream is((char*)sqlite3_column_blob(statement, 0));
boost::archive::binary_iarchive bi(is);
bi >> my_data;
どうも、文字列で受け取る際に先ほどの格納の際と同様の障害が起こっているようです。
理解が浅く応用が効きません、
どのようなコーディングになるのでしょうか。
教えていただけると助かります。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 20:53
by chibago
sqliteにhexと言う関数があり
で16進数の文字列で取り出す所まではいきました。
ただ、今度は16進数を通常のバイナリデータに変換する必要があります。
お分かりになる方は教えていただければ幸いです。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 21:13
by h2so5
chibago さんが書きました:
data()の件は試しましたがダメでした。
std::coutで見る限り(これがダメかもしれませんが)はc_str()と同様の
動作に思えます。
それはstd::coutに出力すると文字列として表示されるからです。
バイナリデータをstd::coutでそのまま出力しても正常に表示されません。
あと、HEXとしてやりとりするのはコマンドラインからSQliteを扱う場合であって、
Cの関数からはそのままバイナリデータで格納できます。
わざわざHEXに変換するのは効率が悪いと思います。
chibago さんが書きました:sqliteにhexと言う関数があり
で16進数の文字列で取り出す所まではいきました。
ただ、今度は16進数を通常のバイナリデータに変換する必要があります。
お分かりになる方は教えていただければ幸いです。
16進数の文字列に変換したものをさらに16進数に変換したら意味がないですよ。
文字列として格納しているのだからそのまま16進数の文字列として取り出せるはずです。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 21:28
by chibago
h2so5 様、
おっしゃるとおりです。
16進数にしたものをさらにHEX関数をかぶせたのは勘違いでした。
コンパイル時の古いオブジェクトファイルが残っていたため混乱してしまいました。
今の課題は、16進数を通常のバイナリへ戻すことです。
確かに、これは効率の悪いものです。
直接バイナリデータデやりとり出来るのが理想です。
ただ、DATA()がダメだったのはCOUTだけでは無く、
プログラムへの実装の方もです。
COUTで見てみたのはより多くの情報を得たかったためです。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 21:31
by h2so5
chibago さんが書きました:
直接バイナリデータデやりとり出来るのが理想です。
ただ、DATA()がダメだったのはCOUTだけでは無く、
プログラムへの実装の方もです。
sqlite3_bind_blobの第五引数にSQLITE_TRANSIENTを指定するとどうでしょうか?
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 21:45
by chibago
h2so5 様、
TRANSIENTでいけました。
ただ、select文で取得されるものは16進数のもの(確かに、わざわざ変換したのはばかばかしいですね。)ですので、何とかBINARYに戻す必要があります。
簡単な方法はございますでしょうか。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 21:49
by h2so5
hex関数を使わずに sqlite3_column_blob を使って直接バイナリで取得できると思います。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 21:56
by chibago
HEXは使っていないんです。
デシリアライズはうまくいかず
std::cout<<(char*)sqlite3_column_blob(statement, 0)<<std::endl;
で吐き出される文字列は16進数のようですので、
sqlite3_column_blobで取得できるのは16進数形式だけ(?)
なのでしょうか。
それとも、凡ミスでしょうか。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 22:05
by h2so5
現状のコードを見せてください。
少なくとも、sqlite3_column_blobを使うとHEX文字列に変換されるという仕様はないようです。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 22:25
by chibago
間違いなく動いているINSERT側です
コード:
std::ostringstream os;
boost::archive::binary_oarchive bo(os);
bo << (const MyData<float>&) info;
std::string query = "insert into my_table(comment, my_data) values('" + comment + "', ? );";
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, query.c_str(),
-1, &statement, 0) == SQLITE_OK){
int rc = 0;
rc = sqlite3_bind_blob(statement, 1, os.str().data(), os.str().length(),
SQLITE_TRANSIENT);
rc = sqlite3_step(statement);
sqlite3_finalize(statement);
}
SELECT側です。
コード:
sqlite3_stmt *statement;
Mydata<float> mi;
std::string query = "select my_data from my_table where comment = '" + comment + "';";
if(sqlite3_prepare_v2(database, query.c_str(),
-1, &statement, 0) == SQLITE_OK){
int rc = sqlite3_step(statement);
std::cout<<(char*)sqlite3_column_blob(statement, 0)<<std::endl;
std::istringstream is((char*)sqlite3_column_blob(statement, 0));
boost::archive::binary_iarchive bi(is);
bi >> mi;
sqlite3_finalize(statement);
}
間違い探しにつき合わせてしまってすみません。
キャスト等は理解せずにサンプルの受け売りですので、
自分でも試行錯誤でためしてみたいとおもいます。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 22:38
by h2so5
std::stringのコンストラクタにバイナリデータを渡すときは、データ長を与える必要があります。
コード:
std::string buffer( (const char*)sqlite3_column_blob(statement, 0), sqlite3_column_bytes(statement, 0) );
std::istringstream is(buffer, istringstream::binary);
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 22:49
by chibago
h2so5 様、
ありがとうございます。
ただ、教えていただいたとおりプログラムを変更しても
デシリアライズには失敗してしまいます。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 22:52
by h2so5
入れたときのバイナリデータと取得したときのバイナリデータをHEXで出力して比較してはどうでしょう。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月19日(火) 23:15
by chibago
入力側はかずま様が教えてくださった変換で、出口はh2so5 様のbufferをCOUTで出したもので
1600000073657269616c697a6174696f6e3a3a6172636869766509000404040801000000000000000004000000746573740100004842
のような形で完全に一致して居ります。
ちなみに、
std::cout<<(char*)sqlite3_column_blob(statement, 0)<<std::endl;
でも同様な出力が得られますので、出口までは正しいデータが来ていると思われます。
ちなみに、sqliteを通さずにシリアライズ、デシリアライズの実績はございまして、
coutで出力する形の
serialization::archive testHB
(コンソール上では見たことのない絵文字のようなものが現れていますが)
のようにならなければならないと思われます。
推測ですが
std::istringstream is(buffer, std::ios::binary);
のbufferはbinary形式に変換されたもの(ORビット列を表したもの)
でなければならないようなきがします。
Re: std::ostringstream に取り込んだバイナリデータのhex表示
Posted: 2012年6月23日(土) 15:25
by chibago
h2so5様、
ありがとうございました。
コードがごちゃごちゃしてきましたので
整理してみたら動きました。
基本的にh2so5様からいただいた情報でいけました。
ありがとうございました。