ファイル操作に関して

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ただの屍のようだ

ファイル操作に関して

#1

投稿記事 by ただの屍のようだ » 13年前

工場でバイトはじめたせいか、牛歩ペースで独学C++を進んでいます。
演習問題で躓きました。プログラム:スタックを作る。メモリ領域ではなく、ディスクファイルに値を格納すること。

コード:

#include<iostream>
#include<fstream>
#include<iomanip>
using namespace std;

class stack{
	fstream *fio;
	int pos;
public:
	stack(){fio=NULL;pos=0;}
	stack(fstream *p){fio=p;pos=0;}
	~stack(){(*fio).close();}				//->演算子でもよかったのですが、.のほうがわかりやすいと思うのでいつもこういう書き方してます。
	void setFile(fstream *p){fio=p;}
	int pop();
	void push(int);
	void show();
};

int stack::pop(){
	int key;
	pos--;
	(*fio).seekg(pos*sizeof(int),ios::beg);
	(*fio).read((char*)&key,sizeof(int));
	//ここでファイルから値一つ消す操作を入れたいです
	return key;
}

void stack::push(int key){
	(*fio).seekp(0,ios::end);
	(*fio).write((char*)&key,sizeof(int));
	pos++;
};

void stack::show(){
	while(pos)	cout << pop() << endl;
}

int main(){
	fstream fio("stk",ios::in | ios::out | ios::binary);
	if(!fio) return 1;
	stack stk(&fio);
	stk.push(5);	stk.push(23);	stk.push(342);	stk.push(11);
	stk.show();
	return 0;
}
どなたかファイルからデータを消す操作、教えて下さい。

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: ファイル操作に関して

#2

投稿記事 by h2so5 » 13年前

ファイルの先頭にスタックの要素数を記録しておき、POPする場合は要素数を減らすだけという方法はどうでしょうか。
あと僕はアロー演算子を使ったほうが分かりやすいと思います。タイプ数も少なくて済みますしね。

ただの屍のようだ

Re: ファイル操作に関して

#3

投稿記事 by ただの屍のようだ » 13年前

先頭に要素数を入れると、効果にたいして処理がめんどくさいので最終手段として使いたいです。

*おそらく突っ込まれるであろうデストラクターについて:『なにも考えずに勢いで作りました。反省してます。』

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ファイル操作に関して

#4

投稿記事 by softya(ソフト屋) » 13年前

少なくとも私はfstreamを極めたわけではないですが、fstreamにファイルサイズを変更するメンバ関数を見たことありません。

> ファイルの先頭にスタックの要素数を記録しておき、POPする場合は要素数を減らすだけという方法はどうでしょうか。

私もスタックをファイル化している意義が薄いと思います。
※ スタックされるのがint限定なら後ろからシークすればposは不要なのでは?とも思います。

> あと僕はアロー演算子を使ったほうが分かりやすいと思います。タイプ数も少なくて済みますしね。

私も*fioよりもfio->を推奨します。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

usao

Re: ファイル操作に関して

#5

投稿記事 by usao » 13年前

特定のファイルについて, スタック的にしかアクセスしないで編集する ということを実現したいだけなら
既存ファイルを読み込む→メモリ上でスタックとして操作する→操作終了時に現結果をファイルに書き出す
ということをすればいいだけですが,
スタックのイメージを絶対に一時たりともメモリ上に持ちたくない とか
pop()で”実際に消す”ということが譲れない(本当は存在として残っているけど消したことにする的な扱いがゆるされない)
とかいうことであれば,1要素毎に1ファイルを作るとかw

ただの屍のようだ

Re: ファイル操作に関して

#6

投稿記事 by ただの屍のようだ » 13年前

ファイルの先頭に要素数を入れると、pop(),push()が頻繁に行われた場合、いちいちカーソルを呼び戻して値をいじるのがめんどくさいです。
あと、ファイルの内容実際に消えるわけではありません(あくまで、書き換えられたり、付け足されたりする)ので。
EOFのsizeof(int)の前でpopすると、常に最後のkeyのみ返されると予想します。

操作として、"\b \b"も考えたのですが、スペースに対する処理がややこしいです。とりあえず、ほかの手段探しながら、次の章へと進みます。

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: ファイル操作に関して

#7

投稿記事 by h2so5 » 13年前

ただの屍のようだ さんが書きました:ファイルの先頭に要素数を入れると、pop(),push()が頻繁に行われた場合、いちいちカーソルを呼び戻して値をいじるのがめんどくさいです。
あと、ファイルの内容実際に消えるわけではありません(あくまで、書き換えられたり、付け足されたりする)ので。
EOFのsizeof(int)の前でpopすると、常に最後のkeyのみ返されると予想します。
EOFは関係なくて要素数を元にseekg, seekpをすれば実際にファイルの内容が消えなくてもデータ構造としては同じ事です。
データ構造において、それが保持しているデータの内容と内部的な構造が一致している必要はないと思います。

要素数を書き換えるのが面倒なのは確かですが、閉じるときにだけ書き換える方法もありますね。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ファイル操作に関して

#8

投稿記事 by softya(ソフト屋) » 13年前

ただの屍のようだ さんが書きました:ファイルの先頭に要素数を入れると、pop(),push()が頻繁に行われた場合、いちいちカーソルを呼び戻して値をいじるのがめんどくさいです。
あと、ファイルの内容実際に消えるわけではありません(あくまで、書き換えられたり、付け足されたりする)ので。
EOFのsizeof(int)の前でpopすると、常に最後のkeyのみ返されると予想します。
問題は、このスタックファイルがプログラムを終えた時に引き続き中身を使用するのかで設計が変わると言うことでしょう。
そこは無視されるんでしょうか?
ただの屍のようだ さんが書きました: 操作として、"\b \b"も考えたのですが、スペースに対する処理がややこしいです。とりあえず、ほかの手段探しながら、次の章へと進みます。
自己完結されているようですが、ちゃんと説明をお願いします。意味が不明です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ただの屍のようだ

Re: ファイル操作に関して

#9

投稿記事 by ただの屍のようだ » 13年前

ファイルをメモリのように使うことが問題の主旨なので、プログラム終了後のデータは破棄します。
破棄しないのであれば、要素数を先頭に保存するべきだと思います。

"\b \b"操作は前の1bitを半角スペースにしてカーソルを1bit前へ戻す。よって
fstream.seekp(0,ios::cur); //シーク操作
for(int i=sizeof(int);i;i--) fstream.write("/b /b"); //カーソル直前のint変数一つをスペースに変える。

そして、スペースを読み飛ばす関数とスペース以外を読み飛ばす関数を用意すればスタックとしては十分機能すると思いますが、もっと簡潔な方法を探しています。

ただの屍のようだ

Re: ファイル操作に関して

#10

投稿記事 by ただの屍のようだ » 13年前

1bit→1byteでした

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ファイル操作に関して

#11

投稿記事 by softya(ソフト屋) » 13年前

ただの屍のようだ さんが書きました:ファイルをメモリのように使うことが問題の主旨なので、プログラム終了後のデータは破棄します。
破棄しないのであれば、要素数を先頭に保存するべきだと思います。
そういう前提なのですね。
ただの屍のようだ さんが書きました: "\b \b"操作は前の1bitを半角スペースにしてカーソルを1bit前へ戻す。よって
fstream.seekp(0,ios::cur); //シーク操作
for(int i=sizeof(int);i;i--) fstream.write("/b /b"); //カーソル直前のint変数一つをスペースに変える。

そして、スペースを読み飛ばす関数とスペース以外を読み飛ばす関数を用意すればスタックとしては十分機能すると思いますが、もっと簡潔な方法を探しています。
エスケープシーケンスでファイル操作可能だと思えないのですが、実験して確認された事項ですか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: ファイル操作に関して

#12

投稿記事 by みけCAT » 13年前

ただの屍のようだ さんが書きました:"\b \b"操作は前の1bitを半角スペースにしてカーソルを1bit前へ戻す。
1bit前に戻すことは考えにくいです。あるとしたら1バイトです。
fstreamがstd::fstreamクラスの変数として、fstream.write("/b /b");はコンパイルエラーになりました。

コード:

D:\(略)\fstreamtest.cpp: In function 'int main()':
D:\(略)\fstreamtest.cpp:10:19: error: no matching function for call to 'std::basic_fstream<char>::write(const char [6])'

D:\kota_documents\Documents\programs\対質問\fstreamtest\fstreamtest.cpp:10:19: note: candidate is:
In file included from c:\mingw4.7.2\bin\../lib/gcc/mingw32/4.7.2/include/c++/ostream:607:0,
                 from c:\mingw4.7.2\bin\../lib/gcc/mingw32/4.7.2/include/c++/istream:41,
                 from c:\mingw4.7.2\bin\../lib/gcc/mingw32/4.7.2/include/c++/fstream:40,
                 from D:\kota_documents\Documents\programs\対質問\fstreamtest\fstreamtest.cpp:1:
c:\mingw4.7.2\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/ostream.tcc:184:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::write(const _CharT*, std::streamsize) [with _CharT = char; _Traits = std::char_traits<char>; std::streamsize = int]
c:\mingw4.7.2\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/ostream.tcc:184:5: note:   candidate expects 2 arguments, 1 provided
また、fio.write("/b /b",strlen("/b /b"));としても前のバイトの削除の効果やカーソル(ファイルポインタのことか?)を戻す効果はありません。
fio.write("\b \b",strlen("\b \b"));も同じです。08 20 08というデータが書き込まれるだけです。
int変数は環境によって異なりますが、4バイトのことが多いと思います。1バイトの可能性は低いです。
スペースを4個書き込んだとしても、それは538976288というint型の値になるだけです。(マジックナンバーとして読み飛ばすことはできます)

ファイルポインタをint型のサイズ分前に戻すには、fio.seekg(-(int)sizeof(int),ios_base::cur);が使えます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: ファイル操作に関して

#13

投稿記事 by ISLe » 13年前

そもそもpushで問答無用にファイル末尾から書き出しているのはなぜですかね。
現在位置を基準にすればシンプルにできるのでは?


関係ないことですが、ドット演算子のほうに慣れているというのはサンプルプログラムくらいしか触れていないってことですよね。

ただの屍のようだ

Re: ファイル操作に関して

#14

投稿記事 by ただの屍のようだ » 13年前

'\b'も手段の一つなのですが、肝心なのは1バイト数値とけしてかぶらない文字があるかどうかです。
だからこそ、ファイルサイズをまずいじろうと思いました。

Cでの現場経験は皆無ですよ

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ファイル操作に関して

#15

投稿記事 by softya(ソフト屋) » 13年前

ただの屍のようだ さんが書きました:'\b'も手段の一つなのですが、肝心なのは1バイト数値とけしてかぶらない文字があるかどうかです。
だからこそ、ファイルサイズをまずいじろうと思いました。
Cでの現場経験は皆無ですよ
テキスト(文字)とバイナリ(2進数)を混同しています。
絶対かぶらないコードは存在しませんよ。

※  みけCATさんが16進数で説明しています。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ただの屍のようだ

Re: ファイル操作に関して

#16

投稿記事 by ただの屍のようだ » 13年前

やはりpushをいじるのがもっとも簡単のようです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: ファイル操作に関して

#17

投稿記事 by softya(ソフト屋) » 13年前

ただの屍のようだ さんが書きました:やはりpushをいじるのがもっとも簡単のようです。
フォーラムルールに有るのですが、質問したコードは解決コードを提示してください。
ここのルールとなっています。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ただの屍のようだ

Re: ファイル操作に関して

#18

投稿記事 by ただの屍のようだ » 13年前

解決したコード載せますよ。(ないほうがましのデストラクターも直しました。)

コード:

#include<iostream>
#include<fstream>
#include<iomanip>
using namespace std;

class stack{
	fstream *fio;
	int pos;
public:
	stack(){fio=NULL;pos=0;}
	stack(fstream *p){fio=p;pos=0;}
	~stack(){fio=NULL;pos=0;}				//->演算子でもよかったのですが、.のほうがわかりやすいと思うのでいつもこういう書き方してます。
	void setFile(fstream *p){fio=p;}
	int pop();
	void push(int);
	void show();
};

int stack::pop(){
	int key;
	pos--;
	(*fio).seekg(pos*sizeof(int),ios::beg);
	(*fio).read((char*)&key,sizeof(int));
	return key;
}

void stack::push(int key){
	(*fio).seekp(pos*sizeof(int),ios::beg);
	(*fio).write((char*)&key,sizeof(int));
	pos++;
}

void stack::show(){
	while(pos)	cout << pop() << endl;
}

int main(){
	fstream fio("stk",ios::in | ios::out | ios::binary);
	if(!fio) return 1;
	stack stk(&fio);
	stk.push(5);	stk.push(23);	stk.push(342);	stk.push(11);
	stk.show();
	fio.close();
	return 0;
}

閉鎖

“C言語何でも質問掲示板” へ戻る