いつもお世話になっております。初質問になりますが宜しくお願いします。
開発はVC6.0のMFCにて行っております。
CString strPath = _T(C:\DATA\表.txt) ;
CString strFileName ;
_splitpath( strPath, NULL, NULL, strFileName.GetBuffer(_MAX_FNAME), NULL)) ;
strFileName.ReleaseBuffer() ;
を実行した場合にstrFileNameには何も入っていない状態になります。
この現象はReleaseで実行した際にのみ発生し、debugでは正常に表が取得できます。
原因としては表の下位コードが\と同じの5cとなっているというところまでは分かってい
ます。
このように\と同じ文字コードの文字が入っているフルパスをフォルダ名やファイル名に
分割する場合、どの様な手法を取ると分割が行えるのでしょうか?
色々検索はしてみたのですが、自分の調べ方が悪いのか解決方法が見つからず困ってお
ります。
どうか宜しくお願い致します。
setlocale( LC_ALL, jpn);
を試してみましたか。
C:\DATA\表.txt はC:\\DATA\\表.txt ですね。
ごめん、
> CString strPath = _T(C:\DATA\表.txt) ;
って、本来のコードでは
> CString strPath = _T(C:\\DATA\\表.txt) ;
になってますよね(確認)。
返信遅れてしまい申し訳ありません。
情報ありがとうございます。
setlocaleについてはどういうものか理解して使用を検討してみたいと思います。
ファイルパスについてはC:\\DATA\\表.txtとなっております。
パス文字の分解で、2バイト文字の処理は結構めんどくさいので私はUNICODEに変換し
て処理しています。(邪道かもしれませんし、速度的な優位性はありません)
CW2A、CA2W(VC6だとW2A、A2Wだったかも)マクロを使うとかなり安易に使えますので、
参考までにどうぞ。
ご質問の内容は、0x5cが出てきた時に'\'なのかトレイルバイトなのかを調べる方法で
しょうか?
上記の話なら文字列をバイト単位で先頭から順番に検査するしかないと思います。
トレイルバイトに0x5cが来ている場合、直前のバイトは必ず2バイトコードのリードバイトの
コードが存在していますから、1バイトずつ検査してリードバイトだった時は、次の1バイトを
トレイルバイトと認識して'\'ではないと判断すれば良いという話だと思います。
リードバイトかどうかを判定する関数はあったはずなので調べてみてください。
そういう話では無いという事でしたら、スルーしてください。
ポイントは
> この現象はReleaseで実行した際にのみ発生し、debugでは正常に表が取得できます。
ですよね。
以下のコードでRelease/debugとも「表」が表示されました。
void func()
{
CString strPath = _T(C:\\DATA\\表.txt);
CString strFileName;
_splitpath(strPath, NULL, NULL, strFileName.GetBuffer(_MAX_FNAME),
NULL);
strFileName.ReleaseBuffer();
AfxMessageBox(strFileName);
}
つまりやり方は間違っていないはず。
みかんさんのコードで気になるところは_splitpath()の最後に余分な)がついている
点。
実際には提示されたコードとは別のコードでやっているんですよね。
(エスケープ文字も抜けていたし。)
原因は提示されていない部分にあるのではないでしょうか?
現象が発生するコードをそのまま提示したら如何でしょう。
皆様、色々とありがとうございます。
setlocaleについてまだ把握し切れていませんが、軽くテストした結果では変化はありま
せんでした。
CW2A、CA2Wについてはまだ理解しきれていない為引き続き調査していこうと思います。
PATIO様の意見ですが、内容的にはそうなるわけですが、今回はファイルのフルパ
スからフォルダ名、ファイル名が分割するというのが目的になっています。
最終的には先頭から一つずつ調査していって分割する関数を作成するという事も視野に
いれて検討してみます。
リードバイトであった場合次のバイトを見てという方法は大変参考になったので是非使
用してみたいと思います。
maru様の意見通り、ReleaseとDebugでの違いもポイントになり、例文もかなり簡単なも
のに変換してあります。
以下実際のコードの流れが分かる様に一部抜き出したものになります。
/**************************************/
void CFileName::Main()
{
CString strProg = _T(") ;
// ここで取得したデータは.\\DATA\\WORK\\1表.TXTとなっています
GetPrivateProfileString( セクション名, キー名, _T("), strProg.GetBuffer
(MAX_PATH), MAX_PATH, パス ) ;
// 関数へ飛ぶ
GetData( strProg ) ;
}
BOOL CFileName::GetWorkSize( CString strProg )
{
// dllにて拡張子を変更する
CString strCalcFile = GetChangeExt( strProg, INI ) ;
// 以下拡張子を変換したファイルを処理
~~~~
return( FALSE ) ;
}
// string = 元ファイル名 ext=変更拡張子
CString FAR PASCAL EXPORT GetChangeExt( CString *string, char *ext )
{
// ファイル名を取り出す
CString strDrive ;
CString strDir ;
CString strFName ;
CString strExt ;
_splitpath( *string, strDrive.GetBuffer( _MAX_DRIVE ),
strDir.GetBuffer( _MAX_DIR ), strFName.GetBuffer( _MAX_FNAME), strExt.GetBuffer
( _MAX_EXT ) ) ;
strDrive.ReleaseBuffer() ;
strDir.ReleaseBuffer() ;
strFName.ReleaseBuffer() ;
strExt.ReleaseBuffer() ;
// 拡張子とファイル名をくっつける
CString retSt = _T(") ;
retSt.Format( _T(%s%s%s.%s), strDrive, strDir, caFName, ext ) ;
return( retSt ) ;
}
/**************************************/
申し訳ありません、コードを書き込む前に読み直したつもりでしたが再度読み直すと最
初の関数へ飛ぶ部分の関数名が間違っていました。
GetDataではなくGetWorkSizeになりますのでご了承ください。
なんだか判断に困るコードだ・・・ツッコミどころ多杉
MBCS なのか UNICODE なのか一度も発言中に明記されていないし
※GetChangeExt の引数は CString* なのか CString なのか判断に困るし
_MAX_PATH と MAX_PATH は意図して使い分けているのかどうか同上
TCHAR と char が混在しているし
警告レベルを上げて警告のある箇所を見直すだけで直る可能性が大とみた。
(発言内容から判断するに MBCS なのだろうから) UNICODE にしてみてエラー・警告の
出る部分を修正するともっとよいと思われる。
tetrapod様の発言通り間違いが多くて申し訳ありません。
文字コードはMBCSで、警告レベルは4になっており、最適化は無効(デバッグ時)にして
います。
ブラウザ情報やデバッグ情報は残さないように設定してあります。
問題の発生しているdllにてテストコードを書いても同様の結果になったのでそのコード
そのままコピーさせて頂きます。
/**************************************/
CString strString = _T(C:\\DATA\\表.txt) ;
// ファイル名を取り出す
CString strDrive ;
CString strDir ;
CString strFName ;
CString strExt ;
CString strData = *string ;
USES_CONVERSION ;
CString strUString = A2W( strString ) ;
_splitpath( strUString, strDrive.GetBuffer( _MAX_DRIVE ),
strDir.GetBuffer( _MAX_DIR ), strFName.GetBuffer( _MAX_FNAME ),
strExt.GetBuffer( _MAX_EXT ) ) ;
strDrive.ReleaseBuffer() ;
strDir.ReleaseBuffer() ;
strFName.ReleaseBuffer() ;
strExt.ReleaseBuffer() ;
/**************************************/
Releaseモードでの取得データ
strDrive=C:
strDir=\DATA\表
strFName=
strExt=.txt
Debugモードでの取得データ
strDrive=C:
strDir=\DATA\
strFName=表
strExt=.txt
UNICODEとMBCSが混ざっちゃってますね。
元のstrStringを、そのまんま_splitpath()に渡せば、
原理的には正しく動くはずです。
// USES_CONVERSION ; いらない
// CString strUString = A2W( strString ) ;いらない
//元の文字列を渡す↓
_splitpath( strString, strDrive.GetBuffer( _MAX_DRIVE ), ・・・
っつうか、CStringの使い方がアウトなので、
リリースの場合ソースのまんまじゃ確かめようがないですね(笑)。
素直に、char配列にしてから試してくださいね。
> 素直に、char配列にしてから試してくださいね。
これに賛成ですね。
MBCSでいいんですよね。
だと、最後にCStringに転送すればいいのですよね。
MBCSでいいのなら文字操作はchar配列のほうがいいように思います。
ただ、char配列は文字数を固定して扱ったほうがいいです。
(余った部分は'\0'で)