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

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

ただいまの
回答率

90.50%

  • C++

    3455questions

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

  • Qt

    141questions

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

[Qt]ドライブ間の移動

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 163

BeatStar

score 1015

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

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

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

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

namespace FileDirectory{
          bool MoveDir( const QString &fromDirpath, const QString &toDirpath ){
               return QFile::rename( fromDirpath, toDirpath );
          }

          bool Exists( const QString &path ){
               // 省略。パスが存在すればtrueを返す。それ以外ならfalse
          }
}

としています。

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

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

// main関数等のような呼び出し元だとして

QString from = "C:/移動元/jazz/hello";
QString to   = "D:/移動先/pops";

if( FileDirectory::Exists( from ) ){
    // 「from + " exists"」と印字する
}

if( FileDirectory::Exists( to ) ){
    // 「to + " exists"」と印字する
}

if( FileDirectory::MoveDir( from, to ) ){
        // "Succeeded!" を印字
}else{
        // "Failed!" を印字
}

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

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

※ 注: 前提として実行ファイルを動かすときは確実にパスが正しいものとします。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で。 ) で

function FileDir(){
              var sf = new ActiveXObject( "Scripting.FileSystemObject" );
              var sh = new ActiveXObject( "WScript.Shell" );
              var sa = new ActiveXObject( "Shell.Application" );

              this.moveDir = function( dirpath1, dirpath2 ){
                             sf.MoveFolder( dirpath1, dirpath2 );
              }
}

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

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

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

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

宜しくお願い致します。


[コメントとして追記]

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

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

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

#include <windows.h>
#include <shellapi.h>

    :
    :

std::string from = R"(C:\移動元\jazz\hello)";
std::string to = R"(D:\移動先\pops)";

// from側の末尾を連続した2個の\0にする
from += '\0';

SHFILEOPSTRUCTA fop{};
fop.wFunc = FO_MOVE;
fop.pFrom = from.c_str();
fop.pTo = to.c_str();
fop.fFlags = FOF_SILENT | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI;

int res = SHFileOperationA(&fop);
printf("%s\n", res == 0 ? "成功" : "失敗");


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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/19 19:26

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

    キャンセル

+1

こんにちは。

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/19 14:40 編集

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

    キャンセル

+1

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/19 19:26

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

    キャンセル

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

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 受付中

    C++ HTMLタグ取り出して分を表示

    HTMLページの<p><p></p></p>で囲まれた文章をC++で表示したいのですが、うまくいきません。 なにか良い方法はありませんか?? 現在こんな感じのプログラムでやって

  • 解決済

    javascriptの変数の値を変えたい

    前提・実現したいこと youtubeを新しいウインドウで開くアドオンを作っています。ウインドウサイズを保存してその大きさのウインドウを開きたいんですがうまくできません。ウインドウ

  • 解決済

    Node.jsから実行中のアプリケーションを取得する

    前提・実現したいこと Electronから、他のアプリケーション実行元のディレクトリを取得したいです 調べたこと かなり調べたのですが、実行中のプロセスを取得するには VBSc

  • 解決済

    Tkinterのwindow

    Tkinterでwindowを画面中央に置く方法を教えてください。 どんなに調べても出てこなかったので... python2.7 macos10.12.6

  • 解決済

    現在開いているEdgeのURLとタイトルを取得したいです。

    こんにちは。  Windows10でC#のアプリケーションを開発しています。  Visual Studio 2017 Communityを使っています。  前提・実現したいこと

  • 解決済

    multimapの参照がうまくできない(C++)

    C++のmultimapにはデータペアを削除する関数がないため、struct v tmp_vのキーに該当する部分をequal_rangeで取り出したのち、その部分からデータがtmp

  • 解決済

    Win32APIのCreateProcess()関数が実行できない

    前提・実現したいこと Win32APIの学習をしています。 プロセス処理について学習を始めようとしたところ、CreateProcess()関数が実行できず、困っています。 発生

  • 解決済

    VBAでmultipart/form-dataでのファイル送信について

    【行いたい動作】 VBAでzipファイルをサーバーにPOSTする 【現状試していること】 VBAでテキストは、POST出来たので multipart/form-data形式に変

同じタグがついた質問を見る

  • C++

    3455questions

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

  • Qt

    141questions

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