お世話になります
自己レスと質問の細くですが、日付を降順にソートする部分は
stable_sort(lineList.begin(), lineList.end(), greater<char*>());
この実装でいいのでしょうか?
ファイル読み込みはそれが最速だと思いますね。その後の実験コードを
示しておきます。エラー処理はしてません
// ソート用の比較関数(コードの降順、日付の昇順)
struct Compare {
bool operator ()(char* p1, char* p2) {
int ret = memcmp(p1+9, p2+9, 4);
if (ret == 0)
return (memcmp(p1, p2, 8) <0);
else return (ret >0);
}
};
// リスト化の部分
pLine = pBuff;
while (pLine && *pLine) {
lineList.push_back(pLine);
pLine = strstr(pLine, \r\n);
if (pLine) {
*pLine = '\0'; // ←出力時の為
pLine += 2;
}
}
// ソート実行の部分
std::stable_sort(lineList.begin(), lineList.end(), Compare());
// ファイル書き出しの部分
hFile = ::CreateFile(d:\\out.txt, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
for (UINT n=0; n<lineList.size(); n++) {
::lstrcpy(szLine, lineList[n]);
::lstrcat(szLine, \r\n);
::WriteFile(hFile, szLine, ::lstrlen(szLine), &dwResult, NULL);
}
::CloseHandle(hFile);
delete [] pBuff;
ファイル出力の部分は1ファイル(勘違いしたまま^^;)なので
すこし格好悪いですが、ループ内でcodeが変わる度に前回ファイルをクローズ、
今回ファイルをオープンする、でどうでしょうか?
> 日付を降順にソートする部分は
> stable_sort(lineList.begin(), lineList.end(), greater<char*>());
> この実装でいいのでしょうか?
おそらくダメ。ポインタを比較しても文字列の比較にはならんでしょ。
FUKUさんεπιστημηさんお世話になります、皆さんのお陰で目的の成果が得られました
>おそらくダメ。ポインタを比較しても文字列の比較にはならんでしょ。
そうですか、イテレータ = ポインタと理解したらいいのかな
約4000ファイルを作成するのに僅か4、5秒で出来ましたWAO!、とても嬉しいですありが
とうございました。
FUKUさんにご教示して頂いたようにfor文の中で異なる、コード名がセットされたら、
ファイルハンドルを破棄し、次のファイル名、ファイルハンドルを取得するように
いたしました、STLの知識が乏しいので古典的なトークン分割とSet、Get関数で
実現しましたがもっとスマートな方法があればご教示して頂ければ嬉しいですが^^;
こんな実装になりました。
HANDLE hFile=::CreateFile(m_FileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL);
if ( hFile==NULL )
return FALSE;
DWORD dwFileSize = GetFileSize(hFile , NULL);
char* pBuff = new char[dwFileSize + 1 ];
static DWORD dwResult;
::ReadFile(hFile, pBuff, dwFileSize, &dwResult, NULL);
// ソート用の比較関数(コードの昇順、日付の降順)
struct Compare {
bool operator ()(char* p1, char* p2) {
int ret = memcmp(p1+9, p2+9, 4);
if (ret == 0)
return (memcmp(p1, p2, 8) > 0);
else return (ret < 0);
}
};
*(pBuff + dwFileSize) = '\0';
vector<char*> lineList;
char* pLine = pBuff;
// リスト化の部分
pLine = pBuff;
while (pLine && *pLine) {
lineList.push_back(pLine);
pLine = strstr(pLine, \r\n);
if (pLine) {
*pLine = '\0';
pLine += 2;
}
}
// ソート実行の部分
std::stable_sort(lineList.begin(), lineList.end(), Compare());
//トークン、セパレータの設定
char *token;
int delimit = ',';
// コード名(ファイル名を取得)
UINT n = 0;
char szBuff[MAX_PATH];
strcpy_s(szBuff, MAX_PATH, ");
// strcpy_s(szBuff,strlen(lineList[ n ]), lineList[ n ]);
::lstrcpy(szBuff, lineList[ n ]);
// 標準のstrtok関数は区切り文字(カンマ)と文字列の間にスペースが無いと巧く動か
ないので
// 自作の関数を使用、それ以外は使い方は標準関数と同じ
fc.mystrtok(szBuff, delimit);
strcpy_s(szBuff, fc.mystrtok(NULL, delimit));
// 初期書込みファイル設定
strncat(szBuff, .txt, 4);
// ファイル名保存用のインライン関数
SetCodeFileName(szBuff);
// ラインバッファー初期化
char szLine[MAX_PATH];
strcpy_s(szLine, MAX_PATH, ");
// ファイル書出し
hFile = ::CreateFile(GetCodeFileName(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
for (n = 0; n < lineList.size(); n++) {
//読込み行からコード名を抽出
strcpy_s(szBuff, MAX_PATH, ");
strcpy_s(szBuff, lineList[ n ]);
fc.mystrtok(szBuff, delimit);
strcpy_s(szBuff, fc.mystrtok(NULL, delimit));
// ファイル名取得用のインライン関数
if(strncmp(szBuff, GetCodeFileName(), 4) == NULL) {
::lstrcpy(szLine, lineList[ n ]);
::lstrcat(szLine, \r\n);
::WriteFile(hFile, szLine, ::lstrlen(szLine), &dwResult,
NULL);
} else {
::CloseHandle(hFile);
strncat(szBuff, .txt, 4);
SetCodeFileName(szBuff);
hFile = ::CreateFile(GetCodeFileName(), GENERIC_WRITE,
FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
n--;
}
}
::CloseHandle(hFile);
delete [] pBuff;
一応ファイル名設定、取得用のインライン関数も記載しておきます^^;
public:
void SetCodeFileName(char * m_cfn){strcpy_s(codeFileame,
MAX_PATH, m_cfn);};
char* GetCodeFileName() {
if(strlen(codeFileame) > 0)
return codeFileame;
else
return NULL;
};
private:
char codeFileame[MAX_PATH];
お世話になりますソイレントグリーンです
あと、例外処理とプログレスバーの実装は自前で行いとりあえず完成ですのでので
解決です^^;
本当にありがとうございました。
尚、先にも書きましたが、strtok関数を用いないようなSTLライクな方法があればご教示
して
頂ければ幸いですし、ここおかしいのでは?等あれば突っ込んでください^^;
なにはともあれ、おめでとう御座います。
しかしファイル書き込みに4~5秒もかかるのは驚きました。
やはりディスクIOのオーバーヘッドは馬鹿にならないという感じですかね。
あと、せっかくなので気になった所を何点か
1 static DWORD dwResult;
今回の処理では変数を静的にする必要は無いと思います。
DWORD dwResult;で充分でしょう
2 char szLine[MAX_PATH];
MAX_PATH(260という値)は普通ファイルパス文字列の処理に使うので
この箇所は別の(1行を格納できる充分な)値にした方が良いと思います。
3 ローカル配列の初期化は
ZeroMemory()やmemset(..0x00..)の方が可読性が高いですね
4 比較関数を処理中に書くのはあまり見たことがありません。
一般的には、以下のような感じでしょうか
比較関数()
{
}
今回の関数()
{
}
まあ、どれも些細な事なので聞き流してもらって良いですが^^;
あ、見逃してた、入力ファイルのクローズが抜けてますね。
::ReadFile()の下行に
::CloseHandle(hFile);
が必要ですよ。
それと、::CreateFile()が失敗した時の戻り値は、
NULLではなくINVALID_HANDLE_VALUEですよね?
> strtok関数を用いないようなSTLライクな方法があれば
ちょいとお試し
----- tokenizer.h -----
#ifndef TOKENIZER_H__
#define TOKENIZER_H__
#include <string> // string
#include <utility> // pair
class tokenizer {
public:
typedef std::pair<std::string::size_type,std::string::size_type> range_type;
explicit tokenizer(const std::string& delimiter);
bool start(const std::string& source);
bool next();
std::string token() const;
range_type range() const;
private:
std::string source_;
std::string delim_;
range_type range_;
};
#endif
----- tokenizer.cpp -----
#include tokenizer.h
tokenizer::tokenizer(const std::string& delim)
: delim_(delim) {}
bool tokenizer::start(const std::string& source) {
source_ = source;
range_.first = 0;
range_.second = 0;
return next();
}
bool tokenizer::next() {
range_.first = source_.find_first_not_of(delim_, range_.first +
range_.second);
if ( range_.first == std::string::npos ) {
return false;
}
range_.second = source_.find_first_of(delim_, range_.first);
if ( range_.second == std::string::npos ) {
range_.second = source_.size() - range_.first;
return true;
}
range_.second -= range_.first;
return true;
}
std::string tokenizer::token() const {
return source_.substr(range_.first, range_.second);
}
tokenizer::range_type tokenizer::range() const {
return range_;
}
----- trial.cpp -----
#include <iostream>
#include tokenizer.h
int main() {
tokenizer t(, );
for ( bool b = t.start(Hello, world); b; b = t.next() ) {
std::cout << t.token() << std::endl;
}
}
FUKUさんεπιστημη(エピステーメー)さんお世話になります
昨日はありがとうございました、時間が経つと成果が得られた嬉しさより
επιστημηさん、FUKUさんに、ご教示して頂いたSTLの魅力にすっかり
取り付かれていましたww
以前は使わず嫌い(食わず嫌い)というか、頭を抱え
「柴田望洋さんの、ポインタを極める」を傍らに置きながら、多次元配列は
作っていたのですが、というか
多次元配列は分かりにくいので、不恰好でも一次元配列をいくつも作って
解決してましたww(これもまた配列を参照する配列とかやりだすと可読性が低くなるんで
すがww)
ところがSTLだとほんの数行でしかも高速に様々な配列処理が出来るのには驚きました。
何度も何度もデッバガーを起動して、ファイルから取り読込まれるデータの様やステップ
インして動作を確認しましたww
それから
FUKUさんダメ出しありがとうございました、修正を入れさせて頂きました。
>NULLではなくINVALID_HANDLE_VALUEですよね?
そうですね-1を返すとMSDNに書いてありました。
if(hFile == INVALID_HANDLE_VALUE)
throw ファイルハンドルの取得に失敗しました;
キャッチハンドラーに投げるようにいたしました。
επιστημηさん
>>ちょいとお試し
ありがとうございます、まだ試していませんが、一行一行熟読して自分のものにしたいと
思います。
しかしSTLって便利ですね。
お世話になります、ソイレントグリーンです
一旦解決したのですが関連する新たな事項がでてまいりました、
新たに起票すべきか迷いましたが、こちらのほうが、話の流れが分かり易いと思い、
ここで質問させて頂きたいとおもいます。申し訳ございません。
現在STLに関して基礎から学びたいので”STL標準講座―標準テンプレートライブラリを利
用したC++プログラミング (Programmer’s SELECTION)”という書籍を
amazonに注文しているのですが、手元にまだ届いてないので申し訳ございませんが、教え
て頂けないでしょうか。
[質問内容です]
お陰さまで、全配列を、日付の昇順で各要素毎に並べ替えは出来たのですが、各要素の数
(各要素の行数)が不定の場合、全要素を一定の数に固定したい場合
どの様なアルゴリズムと手順で考えればいいでしょうか、ご教示願えないでしょうか。
尚、要素数が固定したい数より少ない場合はそのままとする。
データ構造は起票時と同様下記の並びの場合
yymmdd,code,market,high,low,open,close,value
codeをソートキーとした場合、codeの種類毎に数が不定の場合、code毎の要素数を一定に
したい場合です。
> 各要素の数(各要素の行数)が不定の場合、全要素を一定の数に固定したい場合
> どの様なアルゴリズムと手順で考えればいいでしょうか、
質問が理解できません。
要素数がたとえば 3, 4, 5 であるとき、これらをどうしたいのですか?
> データ構造は起票時と同様下記の並びの場合
> yymmdd,code,market,high,low,open,close,value
> codeをソートキーとした場合、codeの種類毎に数が不定の場合、
> code毎の要素数を一定にしたい場合です。
文章が理解できません。日本語になっていません。
挙げられた四つの場合の関連がわかりません。
επιστημηさんお世話になります。
質問が分かり難くてごめんなさい。
具体的にはこういう事です、下記に示す通り
コード番号0101、0201、0301、0401の行数はそれぞれ10、12、13、1行とします。
20070831,0101,i,16270,16569,16266,16569,1840060000
20070830,0101,i,16182,16269,16091,16153,1523490000
20070829,0101,i,16068,16068,15830,16012,1691410000
20070828,0101,i,16214,16343,16192,16287,1331870000
20070827,0101,i,16429,16504,16263,16301,1471220000
20070824,0101,i,16286,16329,16188,16248,1592040000
20070823,0101,i,16093,16333,16093,16316,1805960000
20070822,0101,i,15866,15957,15787,15900,1661020000
20070821,0101,i,15773,16101,15754,15901,2035260000
20070820,0101,i,15477,15940,15477,15732,2244960000
20070831,0201,i,1575,1608,1574,1608,1840060000
20070830,0201,i,1574,1579,1560,1568,1523490000
20070829,0201,i,1562,1562,1537,1557,1691410000
20070828,0201,i,1578,1591,1576,1584,1331870000
20070827,0201,i,1602,1610,1584,1587,1471220000
20070824,0201,i,1587,1591,1578,1585,1592040000
20070823,0201,i,1562,1591,1562,1591,1805960000
20070822,0201,i,1547,1550,1536,1544,1661020000
20070821,0201,i,1532,1565,1531,1549,2035260000
20070820,0201,i,1500,1544,1500,1523,2244960000
20070817,0201,i,1557,1561,1479,1480,2942470000
20070816,0201,i,1576,1576,1529,1567,2676800000
20070831,1301,t1,208,213,208,213,238000
20070830,1301,t1,211,211,208,208,129000
20070829,1301,t1,210,210,207,209,226000
20070828,1301,t1,211,213,211,213,234000
20070827,1301,t1,209,214,207,210,611000
20070824,1301,t1,208,209,207,208,141000
20070823,1301,t1,205,208,204,207,227000
20070822,1301,t1,205,206,202,202,322000
20070821,1301,t1,203,208,203,205,271000
20070820,1301,t1,207,209,202,203,432000
20070817,1301,t1,206,207,200,200,605000
20070816,1301,t1,210,210,205,209,596000
20070815,1301,t1,213,213,211,211,217000
20070831,1401,t1,2,2,2,2,238000
これらを、下記の様に5行にしたいのですが、
但しコード番号1401のように、5行以下の場合は、そのまま(1行)とします。
20070831,0101,i,16270,16569,16266,16569,1840060000
20070830,0101,i,16182,16269,16091,16153,1523490000
20070829,0101,i,16068,16068,15830,16012,1691410000
20070828,0101,i,16214,16343,16192,16287,1331870000
20070827,0101,i,16429,16504,16263,16301,1471220000
20070831,0201,i,1575,1608,1574,1608,1840060000
20070830,0201,i,1574,1579,1560,1568,1523490000
20070829,0201,i,1562,1562,1537,1557,1691410000
20070828,0201,i,1578,1591,1576,1584,1331870000
20070827,0201,i,1602,1610,1584,1587,1471220000
20070831,1301,t1,208,213,208,213,238000
20070830,1301,t1,211,211,208,208,129000
20070829,1301,t1,210,210,207,209,226000
20070828,1301,t1,211,213,211,213,234000
20070827,1301,t1,209,214,207,210,611000
20070831,1401,t1,2,2,2,2,238000
質問の内容理解して頂けたでしょうか、宜しくお願い致します。
5行より多かったときはどの5行を残すのですか?
その条件が提示されていません。
お世話になります。
>5行より多かったときはどの5行を残すのですか?
5行より多かった場合は、日付を基準に新しいものから5行残すことと致します。