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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

2回答

4115閲覧

【C言語】ディレクトリ内のファイルを別ディレクトリに移動

yorha0005

総合スコア14

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

1クリップ

投稿2018/09/30 05:21

編集2018/09/30 08:26

指定ディレクトリにある特定のファイルを別ディレクトリに移動したい

ディレクトリを指定し、そのディレクトリの中にあるファイルの情報を1つずつ読みながら、ある文字列を含むファイルを別ディレクトリに移動させたいです。

例えば、指定ディレクトリ(/Users/name/Downloads)内にあるファイルのうちファイル名に「TESTMOVE」という名前が入ったファイルのみを指定ディレクトリとは別のディレクトリ(/Users/name/Downloads/TESTMOVE)に移動したいときはどう書けばいいでしょうか。

現在、指定文字列の検索(含む、含まないの表示)まではうまくいっていますが、この先が思いつきません。

該当のソースコード

int main(void) { DIR *dir; /* ディレクトリを保存するための変数 */ struct dirent *dp; /* ディレクトリ情報を保存するための構造体宣言 */ char path[64] = "/Users/name/Downloads"; /* 読込先のディレクトリ */ char str1[] = "TESTMOVE"; char newPath[64] = "C:\moveFile/";      /*新しいディレクトリ*/ //①opendir によりファイルをオープン  if ((dir = opendir(path)) == NULL) { perror("opendir"); exit(-1); } //②readdir でディレクトリを読む //『readdir()関数がNULLを返すまで続行』 for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) { printf("%s\n", dp->d_name); //strstr()関数で文字列内の文字検索 if (strstr(dp->d_name, str1) != NULL) { printf("含まれる\n"); //ファイルのディレクトリを移動(ここから) if (MoveFile((LPCTSTR)path,(LPCTSTR)newPath)) { puts("移動しました。"); } else { puts("移動に失敗しました。"); } } else { printf("含まれない\n"); } } //③closedir でディレクトリをクローズ closedir(dir); //コンソールを表示したままにする system("pause"); return 0; }

よろしくお願いいたします。

追記:dp->d_nameが単純にファイル名のみ表示されており、これをrename()とかで名前を変えようかと思ったのですが、dp->d_nameにファイル名しか取得されてないことを考えると単純に「ファイル名」⇒「移動先/ファイル名」みたいに変えてしまっていいのか疑問です。

また、効率のいい方法があったらご教示頂きたいです。

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

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

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

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

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

tiitoi

2018/09/30 05:49

C言語限定でしょうか?C++ でよければ、boost::filesystem を使ったサンプルコードを提示できますが
yorha0005

2018/09/30 06:48

回答ありがとうございます。現状Cも初心者で、C++はわからないです。
tiitoi

2018/09/30 07:13 編集

環境は Linux でしょうか?
yorha0005

2018/09/30 07:35

OSはWindows10です。
guest

回答2

0

ファイル操作は OS 依存の処理になります。
なので、Windows で C 言語のみで書くには、Win32API を使うことになります。
以下に Win32API を使ったサンプルコードを記載しました。
C 言語ではこのようにちょっとしたことをやるにも手間がかかってしまうので、C++ を勉強して boost::filesystem を使ったほうがいいです。

サンプル

環境

  • Windows 10
  • コンパイラ: Visual Studio 2017

以下のディレクトリ構造で試しました。

C: ├─test1 │ ├─ TESTMOVE1.txt │ ├─ TESTMOVE2.txt │ ├─ DONTMOVE1.txt │ └─ DONTMOVE2.txt └─test2

コード

C

1#include <stdio.h> 2 3#include <shlwapi.h> 4#include <windows.h> 5#pragma comment(lib, "shlwapi.lib") // PathCombine 6 7int main() 8{ 9 char srcDirpath[] = "C:\test1"; /* コピー元のディレクトリ */ 10 char dstDirpath[] = "C:\test2"; /* コピー先のディレクトリ */ 11 char str[] = "TESTMOVE"; /* このファイル名を含むファイルをコピーする。 */ 12 13 WIN32_FIND_DATA entry; 14 15 /* "C:\test1" -> "C:\test1*" としている。 */ 16 char srcFilePaths[256]; 17 strcpy(srcFilePaths, srcDirpath); 18 strcat(srcFilePaths, "\*"); 19 20 /* ディレクトリ内の最初のファイルを取得する。 */ 21 HANDLE hFind = FindFirstFile(srcFilePaths, &entry); 22 if (hFind == INVALID_HANDLE_VALUE) { 23 perror("Failed to open directory."); 24 return 1; 25 } 26 27 /* ディレクトリ内のすべてのファイルを取得する。 */ 28 do { 29 if (!strstr(entry.cFileName, str)) 30 continue; /* str がファイル名に含まれない場合 */ 31 32 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 33 continue; /* ディレクトリの場合 */ 34 35 /* "C:\test1" -> "C:\test1\<ファイル名>" としている。 */ 36 char srcFilePath[256]; 37 PathCombine(srcFilePath, srcDirpath, entry.cFileName); 38 39 /* "C:\test2" -> "C:\test2\<ファイル名>" としている。 */ 40 char dstFilePath[256]; 41 PathCombine(dstFilePath, dstDirpath, entry.cFileName); 42 43 /* 移動する。 */ 44 if (!MoveFile(srcFilePath, dstFilePath)) 45 perror("Failed to move file: %s -> %s.", srcFilePath, dstFilePath); 46 printf("move: %s -> %s\n", srcFilePath, dstFilePath); 47 48 } while (FindNextFile(hFind, &entry)); 49 FindClose(hFind); 50} 51

投稿2018/09/30 08:31

tiitoi

総合スコア21956

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

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

0

うん?
ここまで来れば単純に移動するだけじゃない?
何がわからないのでしょうか?
「どういう関数を使えばファイルを移動できるか」でしょうか?
それとも「どうやって移動先や移動前のファイルパスを確定するか」でしょうか?
ディレクトリ内にあるファイルを列挙すること自体ができない(どの関数を使えばいいか...)ならまだわかりますが、ここまで来たらあと一息でしょ。


[追記1]
reply読みました。

ということは
■ どの関数を使えばいいか
■ どのように移動先を決定するか
ですね。

これはWindows限定でしょうか? それともMac限定? それともコンパイルし直せばどのOSでも使えるようにするのでしょうか?

もし Windows限定なら Windows APIを使うっていう手もありますよ。

関数自体は ファイル名変更、移動、削除、存在確認によると普通にrename関数で良いみたいです。

移動先は単純に指定...って思いましたがよく読んだらいわゆる特殊フォルダですね。

調べてみましたが、ちょっと厳しいみたいです。Windows APIを前提としているか、C++を前提としていますね。

絶対にC言語で、WinAPI ( Windows API ) を使わない方法でっていうなら、

方法1: JavaやC#, PythonのCUIタイプ(コンソールのやつ)でいったん取得して、その言語のソフトから本体であるC言語で作成したソフトを起動。っていう風にする。 Javaのソフト起動 -> Java側で特殊フォルダ取得 -> 特殊フォルダをコマンドライン引数として C言語で組んだソフトを起動 のような状態。
方法2: 方法1のDLL版。C#での特殊フォルダ取得系のやつをDLL化しておいてそれをC言語側で呼び出す。 ただし、こちらはかなり労力を必要とし、なおかつJavaとC言語の連携のような感じの場合はかなり組むのが大変になり、またC++の基礎も必要になることが多い。
方法3: Qt等のようなライブラリ( Widgetツールキットっていうらしいですが。 ) を使って行う。 ただし、C++の基礎が必要になってくることが多い。
方法4: コンソール入力かコマンドライン引数によって取得する。 例えばソフト名を Mover.exe としたら rem Mover 移動元 移動先 Mover C:\TestFiles C:\TestFiles\編集後 のような感じで。 ただし、こちらはユーザがPCの知識がないと厳しい。 パス自体わかっていない人が多いから。( 私もプログラミングやるまではわかっていませんでした。 )
方法5: 特殊フォルダじゃなくて普通の決め打ちできそうな位置にする。 例えば Windowsフォルダじゃなくて Cドライブ直下とかね。 ただし、Cドライブ直下にはOSバージョンによっては作成したりできない場合がある。
方法6: 諦めてC++かJava, C# のような別の言語に切り替える C++であれば拡張子を cppにしておけば C言語とC++で一応両立は可能。 ただし、constの扱いとかが違ってきたりするが。
方法7: Windows APIを使う

の方法7以外になるね。


[追記2]
MoveFile関数をお読みになりました?
戻り値は何になっていますか? GetLastError関数っていうのを使ってエラー番号を取得するみたいです。( 私は使ったことないですが。 )

多分、

■ 指定した移動元のパスが間違っている
■ 指定した移動先のパスが間違っている
■ 書き方が例えば半角スペースを含んだ文字列のためソフト( いや、OSか? )が勘違いしている

があり得ますね。3つ目は特に コマンドプロンプトで ファイルパスを渡すときに発生します。
なので含めました。 

多分1,2のどれかだと思う。

実際に何らかの関数 ( printf関数, puts関数 等 ) でそれぞれ表示してみてください。
もしかしたら存在しないパスを指定しているとかじゃないかなと。

また、特殊フォルダ ( Windowsフォルダ等 ) はPCによって違ってくるので決め打ちはしないほうがいいです。
「Windows API 特殊フォルダ 取得」みたいにして検索すればサンプルが出てきます。
著作権を侵害しない程度にやってみてください。

投稿2018/09/30 06:12

編集2018/09/30 08:58
BeatStar

総合スコア4958

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

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

yorha0005

2018/09/30 07:01 編集

回答ありがとうございます。初心者なので、何とかここまでは作ったのですが、多分「どういう関数を使えばファイルを移動できるか」も「どうやって移動先や移動前のファイルパスを確定するか」もよくわかってなくて、移動の方法はrenameとかで名前を変えるのか、そもそも移動先のファイルパスを単純に名前につければでぃれくとりがかわるのか分からないです。
BeatStar

2018/09/30 07:04

追記します。↑
yorha0005

2018/09/30 08:30

詳細なご回答、ありがとうございます。なんとか素人ながらかみ砕いてみた結果、Windows APIを使用することにしました。ソースも修正しましたが、今のところ成功はしておりません。コンパイルは通りましたが、「移動に失敗しました。」が表示されるため、MoveFile()関数をうまく使えてない?か、先ほどあったように特殊ファルダ?が原因でしょうか。 もしまたお力添え願えましたらよろしくおねがいいたします。
a_saitoh

2018/09/30 09:13

Windowsの場合、ファイルをcloseしてからでないと動かせないとおもいますよ。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問