1. 要件の説明 Linux システムの複数のディレクトリに、同じプレフィックスとサフィックスを持つファイルがいくつかあります。それらを同じディレクトリに移動するプログラムを作成してください。 たとえば、FileDir1、FileDir2、FileDir3 という 3 つのソース ディレクトリがあり、それぞれに File_1.txt、File_2.txt、File_3.txt というファイルが含まれています。これら 3 つのファイルはプレフィックス (File_) とサフィックス (txt) が同じなので、同じ結果ディレクトリ (GatherDir であると仮定) に移動されます。 2. アルゴリズム設計 要件に基づいて、図 1 に示すプログラム フローを採用できます。 図1 全体的なプロセスフロー 3. 特別なプロセスに関する考慮事項 プログラムを作成する過程では、次のような特別なプロセスが考慮されます。 1. ディレクトリのスキャン中にエラーが発生した場合、プログラムは次のディレクトリをスキャンせずに停止します。 2. 空のファイル(つまり、ファイル サイズが 0)がある場合は、結果ディレクトリに移動せずに、ソース ディレクトリで直接削除します。 3. ソース ディレクトリに配置されたファイルをいつでも処理できるように、プログラムはソース ディレクトリを一定の間隔 (1 分など) でスキャンします。つまり、人間による操作がなければ、プログラムは起動後継続的に実行されます。 4. プログラムコード - /******************************************************************************************
- * 著作権 (C) 2016、Zhou Zhaoxiong。
- *
- * ファイル名: FileGather.c
- * ファイルID: なし
- * コンテンツの概要: さまざまなディレクトリにある同じプレフィックスを持つファイルを 1 つのディレクトリに集めます
- * その他の指示: なし
- * 現在のバージョン: V1.0
- * 著者: 周昭雄
- * 完成日: 20160513
- *
- ******************************************************************************/
- #include <stdio.h>
- #include <文字列.h>
- #include <dirent.h>
- #include <ftw.h>
- #include <時間.h>
-
- // データ型を再定義する
- typedef 符号付きint INT32;
- typedef 符号なしint UINT32;
- typedef unsigned char UINT8;
-
- //グローバル変数の定義
- UINT8 g_szGatherDir[256] = {0}; // サマリーファイルのディレクトリ
- UINT8 g_szFilePrefix[20] = {0}; // 要約するファイルのプレフィックス
- UINT8 g_szFileSuffix[20] = {0}; // 要約するファイルのサフィックス
-
-
- // マクロ定義
- #define DIRNUM 3 // スキャンするディレクトリの数
-
- // 関数宣言
- INT32 SelectFlies(構造体 dirent *pDir);
- void スキャンディレクトリと収集(void);
- void スリープ(UINT32 iCountMs);
-
-
- /****************************************************************
- * 機能説明: 主な機能
- * 入力パラメータ: なし
- * 出力パラメータ: なし
- * 戻り値: 0 - 実行完了
- * その他の指示: なし
- * 変更日 バージョン番号 修正者 変更内容
- *
- * 20160513 V1.0 作成者: Zhou Zhaoxiong
- ************************************************************************/
- INT32メイン(void)
- {
- // サマリーファイルのディレクトリを取得する
- snprintf(g_szGatherDir, sizeof(g_szGatherDir)-1, "%s/zhouzx/TestDir/GatherDir" , getenv( "HOME" ));
-
- // 要約するファイルのプレフィックスを取得します
- snprintf(g_szFilePrefix, sizeof(g_szFilePrefix)-1, "File_" );
-
- // 要約するファイルのサフィックスを取得します
- snprintf(g_szFileSuffix, sizeof(g_szFileSuffix)-1, ".txt" );
-
- // 呼び出し関数実行ファイルの概要
- (1)
- {
- スキャンディレクトリと収集();
-
- Sleep(60 * 1000); // 1分ごとにファイルサマリーを実行する
- }
-
- 0を返します。
- }
-
-
- /******************************************************************************************
- * 機能の説明: プレフィックスとサフィックスに基づいてファイルを選択する
- * 入力パラメータ: dir-ディレクトリ
- * 出力パラメータ: なし
- * 戻り値: 0-失敗、1-成功
- * その他の指示: なし
- * 変更日 バージョン番号 修正者 変更内容
- *
- * 20160513 V1.0 作成者: ZhouZhaoxiong
- ******************************************************************************/
- INT32 SelectFlies(構造体 dirent *pDir)
- {
- INT32 iPrefixLen = 0;
- INT32 iループフラグ = 0;
- INT32 iSelectResult = 0;
-
- (pDir == NULL )の場合
- {
- printf( "SelectFlies:入力パラメータがNULLです!\n" );
- 0を返します。
- }
-
- // ファイルのプレフィックスとサフィックスを一致させる
- iPrefixLen = strlen(g_szFilePrefix); // プレフィックスはg_szFilePrefixです
- iSelectResult = ((0 == strncmp(pDir->d_name, g_szFilePrefix, iPrefixLen))
- && ((strncmp(&pDir->d_name[strlen(pDir->d_name) - strlen(g_szFileSuffix)], g_szFileSuffix, strlen(g_szFileSuffix)) == 0)));
-
- if (iSelectResult == 1) // プレフィックスに一致するファイルが見つかりました
- {
- 1 を返します。
- }
- それ以外
- {
- 0を返します。
- }
- }
-
-
- /******************************************************************************************
- * 機能の説明: ディレクトリをスキャンし、同じプレフィックスを持つファイルを要約します
- * 入力パラメータ: なし
- * 出力パラメータ: なし
- * 戻り値: なし
- * その他の指示: なし
- * 変更日 バージョン番号 修正者 変更内容
- *
- * 20160513 V1.0 作成者: ZhouZhaoxiong
- ******************************************************************************/
- void スキャンディレクトリと収集(void)
- {
- INT32 iScanDirRet = 0;
- UINT32 iDirIdx = 0;
- UINT32 iFileIdx = 0;
- UINT32 iFileCount = 0;
- UINT32 iScanedNoFileDirCount = 0;
- UINT32 iFileSize = 0;
- INT32 iRetVal = 0;
- UINT8 szFileDir[256] = {0};
- UINT8 szScanedFile[512] = {0};
- UINT8 szCmdBuf[256] = {0};
- ファイル *fp = NULL ;
- 構造体 dirent **ppDirEnt = NULL ;
-
- // 各ディレクトリを順番にスキャンしてファイルを要約します
- (iDirIdx = 1; iDirIdx <= DIRNUM; iDirIdx ++)の場合
- {
- memset(szFileDir, 0x00, sizeof(szFileDir));
- snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir%d" 、getenv( "HOME" 、iDirIdx);
-
- iScanDirRet = scandir(szFileDir, &ppDirEnt, SelectFlies, alphasort);
- if (iScanDirRet < 0) // ディレクトリのスキャン中にエラーが発生しました
- {
- printf( "ScanDirAndGather:exec scandir が失敗しました。パス=%s\n" , szFileDir);
- 戻る;
- }
- else if (iScanDirRet == 0) // ディレクトリにファイルがありません
- {
- printf( "ScanDirAndGather:ディレクトリ%sに条件に合うファイルがありません\n" , szFileDir);
-
- スキャンされたファイルディレクトリ数++;
- if (iScanedNoFileDirCount >= DIRNUM) // すべてのディレクトリに条件を満たすファイルが存在しないことを示します
- {
- printf( "ScanDirAndGather: %d 個のディレクトリすべてで条件に合うファイルがスキャンされませんでした\n" , iScanedNoFileDirCount);
- 戻る;
- }
- }
- else // 条件を満たすファイルをサマリーディレクトリに移動する
- {
- (iFileIdx = 0; iFileIdx < iScanDirRet; iFileIdx ++)の場合
- {
- // まずスキャンしたファイルが空ファイルかどうかを判断し、空ファイルの場合は直接削除し、空ファイルでない場合は移動操作を実行します
- memset(szScanedFile, 0x00, sizeof(szScanedFile));
- snprintf(szScanedFile, sizeof(szScanedFile) - 1, "%s/%s" , szFileDir, ppDirEnt[iFileIdx]->d_name);
- fp = fopen(szScanedFile, "r" );
- if (fp == NULL ) // ファイルを開けなかった場合は直接戻ります
- {
- printf( "ScanDirAndGather:ファイル%sのオープンに失敗しました。確認してください!\n" , szScanedFile);
- 戻る;
- }
- fseek(fp, 0, SEEK_END);
- ファイルサイズ = ftell(fp);
- if (iFileSize == 0) // ファイルは空のファイルです
- {
- printf( "ScanDirAndGather:%s は空のファイルなので、直接削除してください!\n" , szScanedFile);
- memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
- snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "rm %s" , szScanedFile);
- システム(szCmdBuf);
- }
- それ以外
- {
- memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
- snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "mv %s %s" , szScanedFile, g_szGatherDir);
- システム(szCmdBuf);
-
- printf( "ScanDirAndGather:now, %s\n" , szCmdBuf);
-
- ファイルカウント++;
- }
- }
- }
- }
-
- printf( "ScanDirAndGather: 今回は合計 %d 個のファイルを %s に移動しました\n" , iFileCount, g_szGatherDir);
-
- 戻る;
- }
-
-
- /******************************************************************************************
- * 機能説明: プログラム休止状態
- * 入力パラメータ: iCountMs - スリープ時間 (単位: ms)
- * 出力パラメータ: なし
- * 戻り値: なし
- * その他の指示: なし
- * 変更日 バージョン番号 修正者 変更内容
- *
- * 20160513 V1.0 作成者: Zhou Zhaoxiong
- ****************************************************************************/
- void スリープ(UINT32 iCountMs)
- {
- 構造体timeval t_timeout = {0};
-
- (iCountMs < 1000)の場合
- {
- t_timeout.tv_sec = 0;
- t_timeout.tv_usec = iCountMs * 1000;
- }
- それ以外
- {
- t_timeout.tv_sec = iCountMs / 1000;
- t_timeout.tv_usec = (iCountMs % 1000) * 1000;
- }
- select (0, NULL , NULL , NULL , &t_timeout); // select関数を呼び出してプログラムをブロックする
- }
5. プログラムのテスト 記述したプログラム「FileGather.c」を Linux マシンにアップロードし、「gcc -g -o FileGather FileGather.c」コマンドを使用してプログラムをコンパイルし、「FileGather」ファイルを生成します。以下はプログラムの詳細なテストです。 1. プログラムを起動する前に、File_1.txt、File_2.txt、File_3.txt の各ファイルをそれぞれソース ディレクトリ FileDir1、FileDir2、FileDir3 に配置します。プログラムは次のように実行されます。 - ScanDirAndGather:今、mv /home/zhou/zhouzx/TestDir/FileDir1/File_1.txt /home/zhou/zhouzx/TestDir/GatherDir
- ScanDirAndGather:今、mv /home/zhou/zhouzx/TestDir/FileDir2/File_2.txt /home/zhou/zhouzx/TestDir/GatherDir
- ScanDirAndGather:今、mv /home/zhou/zhouzx/TestDir/FileDir3/File_3.txt /home/zhou/zhouzx/TestDir/GatherDir
- ScanDirAndGather:今回は合計3つのファイルを/home/zhou/zhouzx/TestDir/GatherDirに移動しました
ご覧のとおり、ソース ディレクトリ内の 3 つのファイルは存在しなくなりました。これらは結果ディレクトリ GatherDir に移動されました。 - ~/zhouzx/TestDir/GatherDir>ll
- -rw——- 1 zhou users 12 2016-05-13 15:14 File_1.txt
- -rw——- 1 zhou users 12 2016-05-13 15:14 File_2.txt
- -rw——- 1 周 ユーザー 12 2016-05-13 15:14 File_3.txt
2. しばらくしてから、ファイル File1_4.txt をソース ディレクトリ FileDir1 に配置すると、プログラムは次のように実行されます。 - ScanDirAndGather:ディレクトリ /home/zhou/zhouzx/TestDir/FileDir1に条件に合うファイルがありません
- ScanDirAndGather:ディレクトリ /home/zhou/zhouzx/TestDir/FileDir2に条件に合うファイルがありません
- ScanDirAndGather:ディレクトリ /home/zhou/zhouzx/TestDir/FileDir3に条件に合うファイルがありません
- ScanDirAndGather: 条件に合うファイルがスキャンされませんでした 全3ディレクター
ご覧のとおり、プレフィックスが一致しないため、File1_4.txt ファイルはソース ディレクトリ FileDir1 に残っています。 - ~/zhouzx/TestDir/FileDir1>ll
- -rw——- 1 周 ユーザー 36 2016-05-13 15:19 File1_4.txt
3. しばらくしてから、File_5.txt ファイルをソース ディレクトリ FileDir2 に置き、File_11.c ファイルをソース ディレクトリ FileDir3 に置きます。プログラムは次のように実行されます。 - ScanDirAndGather:ディレクトリ /home/zhou/zhouzx/TestDir/FileDir1に条件に合うファイルがありません
- ScanDirAndGather:今、mv /home/zhou/zhouzx/TestDir/FileDir2/File_5.txt /home/zhou/zhouzx/TestDir/GatherDir
- ScanDirAndGather:ディレクトリ /home/zhou/zhouzx/TestDir/FileDir3に条件に合うファイルがありません
- ScanDirAndGather:今回は合計 1 つのファイルを/home/zhou/zhouzx/TestDir/GatherDirに移動しました
ソース ディレクトリ FileDir2 内のファイル File_5.txt はサフィックスが一致しないため存在しなくなり、ソース ディレクトリ FileDir3 内のファイル File_11.c はまだ存在していることがわかります。 - ~/zhouzx/TestDir/FileDir3>ll
- -rw——- 1 zhou users 4 2016-05-13 15:23 File_11.c
File_5.txt は結果ディレクトリ GatherDir に移動されました: - ~/zhouzx/TestDir/GatherDir>ll
- -rw——- 1 周 ユーザー 12 2016-05-13 15:14 File_1.txt
- -rw——- 1 zhou users 12 2016-05-13 15:14 File_2.txt
- -rw——- 1 周 ユーザー 12 2016-05-13 15:14 File_3.txt
- -rw——- 1 周 ユーザー 36 2016-05-13 15:23 File_5.txt
4. しばらくすると、空のファイル File_7.txt がソース ディレクトリ FileDir2 に配置され、プログラムは次のように実行されます。 - ScanDirAndGather:ディレクトリ /home/zhou/zhouzx/TestDir/FileDir1に条件に合うファイルがありません
- ScanDirAndGather:/home/zhou/zhouzx/TestDir/FileDir2/File_7.txt は空のファイルなので、直接削除してください。
- ScanDirAndGather:ディレクトリ /home/zhou/zhouzx/TestDir/FileDir3に条件に合うファイルがありません
- ScanDirAndGather: 今回は、合計 0 個のファイルを/home/zhou/zhouzx/TestDir/GatherDirに移動しました
ソース ディレクトリ FileDir2 内のファイル File_7.txt が削除されたことがわかります。 - ~/zhouzx/TestDir/FileDir2>ll
- 合計 0
6. 需要拡大 この記事の要件と手順に基づいて、要件に対する次の拡張を検討できます。 1. ファイルを移動する前に、結果ディレクトリに同じファイル名のファイルが存在するかどうかを確認します。存在する場合は、ソースディレクトリからファイルを直接削除します。存在しない場合は、ファイルを結果ディレクトリに移動します。 2. 結果ディレクトリ内のファイルが多すぎるのを避けるために、プログラムにクリーンアップ メカニズムを追加して、一定期間以上保存されているファイルを削除することができます。 3. プログラムの柔軟性を反映するために、一部のファイル情報(ファイルのプレフィックス、サフィックス、保存ディレクトリ、スキャン間隔など)を設定ファイルに保存できます。プログラムが起動すると、関連する設定項目の値が読み取られ、後続のディレクトリスキャンとファイル移動操作が実行されます。 [この記事は51CTOコラムニストの周兆雄氏によるオリジナル記事です。著者のWeChat公開アカウント:周の論理(logiczhou)] この著者の他の記事を読むにはここをクリックしてください |