質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

4163閲覧

[Qt]ドライブ間の移動

BeatStar

総合スコア4958

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/07/19 02:37

編集2018/07/19 10:29

ちょっと気になったので質問します。( 趣味でC++やっています。 )

前提としてOSは Windowsオンリーとさせて頂きます。( 他のOSの方もご回答されてもいいですが、
Windows上の話だと思うので指定させて頂きます。 バージョンは開発時は Win10で 使用は Win7もあり得ます。 )

Qtの QFile::rename() を使って ディレクトリを丸ごと移動したいと思っています。

関数名とやりたいことがアレなため、ラップして

C++

1namespace FileDirectory{ 2 bool MoveDir( const QString &fromDirpath, const QString &toDirpath ){ 3 return QFile::rename( fromDirpath, toDirpath ); 4 } 5 6 bool Exists( const QString &path ){ 7 // 省略。パスが存在すればtrueを返す。それ以外ならfalse 8 } 9}

としています。

このFileDirectory::MoveDir関数 ( 元は QFile::rename関数 ) を呼び出してディレクトリ丸ごと移動したいと思っています。

で、ここまではいいのですが、なぜかパーティション? っていうのでしょうか? ドライブが違うと常に失敗します。

C++

1// main関数等のような呼び出し元だとして 2 3QString from = "C:/移動元/jazz/hello"; 4QString to = "D:/移動先/pops"; 5 6if( FileDirectory::Exists( from ) ){ 7 // 「from + " exists"」と印字する 8} 9 10if( FileDirectory::Exists( to ) ){ 11 // 「to + " exists"」と印字する 12} 13 14if( FileDirectory::MoveDir( from, to ) ){ 15 // "Succeeded!" を印字 16}else{ 17 // "Failed!" を印字 18}

のような状態にしています。

( ディレクトリパスは適当。 )

※ 注: 前提として実行ファイルを動かすときは確実にパスが正しいものとします。toはQtの関数を使うときは新規ディレクトリとしてやっています。
その上、移動先ディレクトリはCドライブとDドライブの構成(ドライブ以外の新規ディレクトリまでのパス)は完全に同じであり、
単にドライブ名をC -> Dにしただけとします。また、Dドライブ及びCドライブは存在するものとします。
つまり、ドライブ名以外は完全に同じであり、移動元が無いなどのような「どうやっても失敗する」タイプではないとします。
少なくともDドライブになっているQString fromのパスをCドライブに変えると成功することから、今回の質問に。
( ソースコードのようには証明できないことと、外出先から質問しているので証明はできませんが。 )

これを動かすと Exists系のやつがfrom が true で to が falseになっています。

でFileDirectory::MoveDir関数の結果としては "Failed!" が印字されます。

その(最終的な)パス(つまりtoか。)を確認しても「存在しません」。

で、これの QString to の ドライブ名を Dドライブから Cドライブに変えると (つまり移動元,移動先は同じドライブになる)

"Succeeded!" と印字されて toのパスを実際にチェックすると移動が完了しています。

一応、今作っている作品は自分用で、同じドライブからしか...でも問題ないのでいいですが、

USBとかに入れて使っていて、Cドライブとかの他のドライブに移動したい場合はそのソフトが入っているディレクトリ一式をCドライブに移動しないと

いけないので面倒です。

これってどうにかできませんか?

最近 ( と言っても3か月以上も前かな? ) PCを買い換えて Win10にしたところ、

Cドライブ直下にファイルは置けなくなってしまいました。

( セキュリティ面の問題を回避するためだろうけど。 )

そういう風にセキュリティ面で問題だからあえて「ドライブ間の移動は不可能」にしてあるのでしょうか?

できれば プログラマ(私)だけでどうにか出来たらいいのですが...

(例えば 第三引数として 「ドライブ間の移動やコピー等を許可する」とかみたいにするとか、
ロケール設定みたいに 「ドライブ間の移動やコピー等を許可する」関数を動かす -> 実際に移動したりする みたいに。 )

ちなみに JScript ( WSH ) ( WSFで。 ) で

JavaScript

1function FileDir(){ 2 var sf = new ActiveXObject( "Scripting.FileSystemObject" ); 3 var sh = new ActiveXObject( "WScript.Shell" ); 4 var sa = new ActiveXObject( "Shell.Application" ); 5 6 this.moveDir = function( dirpath1, dirpath2 ){ 7 sf.MoveFolder( dirpath1, dirpath2 ); 8 } 9}

のようにして試してみましたが、C++&Qtのときと同じようにしても大体同じ結果でした。

JScriptでうまく行くなら最悪、C++&Qtのプロセス起動系のやつとかでJScriptにコマンドライン引数として渡して...とできますが、
JScriptでも同じだったので...

どのようにすればいいのでしょうか?

[情報]
言語: C++ ( C++11 )
コンパイラ: MinGW
Qt: Qt 5.6 (LGPL)
OS: Windows (開発自体はWin10で使用はWin10,Win7,WinXPの場合もある。他OSは考慮しない。)

宜しくお願い致します。


[コメントとして追記]

皆様、ご回答ありがとうございます。
皆様の回答どれもよかったのですが、具体策を提示されたcatsforepawさんの回答をベストアンサーとします。
ご協力ありがとうございます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

セキュリティ上の問題ではなく、実装の問題です。
moveの実装は、ディスク上の管理領域(ディレクトリエントリやMFTなど)のみ書き換えることで、別のフォルダに移動するかたちになります。
こうすることで、ファイルの実体部分には手を付けずに済みます。
移動にかかる時間が少なくて済むだけでなく、空き領域がほとんどなくても移動可能というメリットがあります。(コピーしてから元ファイルを削除することで移動する場合は、同一ドライブだと対象ファイルと同容量の空き領域が必要になります)

投稿2018/07/19 07:35

m-take

総合スコア249

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2018/07/19 10:26

ご回答ありがとうございます。 それでなのですね。
guest

0

ベストアンサー

Windows APIの直接呼び出しを許容するのであれば、Shell APIのSHFileOperation関数で別ドライブへのディレクトリーの移動が可能です。

コード例 (※ご質問のコードのパスがANSI文字列なので、ANSI版の関数を呼び出しています)

c++

1#include <windows.h> 2#include <shellapi.h> 3 4 : 5 : 6 7std::string from = R"(C:\移動元\jazz\hello)"; 8std::string to = R"(D:\移動先\pops)"; 9 10// from側の末尾を連続した2個の\0にする 11from += '\0'; 12 13SHFILEOPSTRUCTA fop{}; 14fop.wFunc = FO_MOVE; 15fop.pFrom = from.c_str(); 16fop.pTo = to.c_str(); 17fop.fFlags = FOF_SILENT | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI; 18 19int res = SHFileOperationA(&fop); 20printf("%s\n", res == 0 ? "成功" : "失敗"); 21

気をつける点としては、パスの区切り文字がスラッシュ(/)だと失敗します。また、from側のパス文字列の最後は、null終端文字(\0)が2個必要です。

投稿2018/07/19 06:55

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2018/07/19 10:26

ご回答ありがとうございます。 やっぱりWinAPIですかね。
guest

0

こんにちは。

move系のファイル操作は多くのOSで同じドライブでないとダメだった筈です。(linuxでも同様だったような。move系の操作はハードリンクのすげ替えと同じような操作ですので。)

そして、Qtのファイル/ディレクトリ操作系の関数は、プリミティブなものしかない(先日フォルダのまるごとコピーしたのですが、結構手間がかかりました)ので、ディレクトリを移動する関数はOSの持つmove機能を呼び出しているだけの可能性が高いです。
ですので、ドライブをまたぐ場合は、再帰的にコピーし、コピー元を再帰的に削除するアルゴリズムを自力で作るしかないだろうと思います。
Windows限定であれば、xcopyでコピーし、rd /S /Qで削除すると簡単と思います。

投稿2018/07/19 05:26

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2018/07/19 05:41 編集

ご回答ありがとうございます! やはりシェルっていうのでしょうか? CMDで使えるやつをsystem関数辺りで呼び出して...か。 それか再帰的にコピー -> 再帰的削除 ... ですか。なるほど。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問