1. 要件の説明 Linux システムのソース ディレクトリには、同じサフィックスを持つファイルがいくつかあります。これらのファイルをプレフィックスに応じて異なるディレクトリに分散するプログラムを作成してください。 たとえば、同じサフィックスを持つ 3 つのファイル File1_1.txt、File2_1.txt、File3_1.txt がソース ディレクトリ SourceDir に保存されているとします。プレフィックス File1_、File2_、File3_ に従って、これらのファイルはそれぞれディレクトリ FileDir1、FileDir2、FileDir3 に移動 (配布) されます。 2. アルゴリズム設計 要件に基づいて、図 1 に示すプログラム フローを採用できます。 図1 全体的なプロセスフロー 3. 特別なプロセスに関する考慮事項 プログラムを作成する過程では、次のような特別なプロセスが考慮されます。 1. ソース ディレクトリのスキャン中にエラーが発生した場合、プログラムは次のディレクトリのスキャンを続行せずに実行を停止します。 2. 空のファイル(サイズが 0 のファイル)がある場合は、配布せずにソース ディレクトリで直接削除します。 3. ソース ディレクトリに配置されたファイルをいつでも処理できるように、プログラムはソース ディレクトリを一定の間隔 (1 分など) でスキャンします。つまり、人間による操作がなければ、プログラムは起動後継続的に実行されます。 4. プログラムコード - /******************************************************************************************
- * 著作権 (C) 2016、Zhou Zhaoxiong。
- *
- * ファイル名: FileDistribute.c
- * ファイルID: なし
- * 内容の概要: ディレクトリ内のファイルをプレフィックスに従って対応するディレクトリに配布する
- * その他の指示: なし
- * 現在のバージョン: V1.0
- * 著者: 周昭雄
- * 完成日: 20160517
- *
- ******************************************************************************/
- #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_szSourceDir[256] = {0}; // ソースファイルのディレクトリ
-
- // 関数宣言
- INT32 SelectFlies(構造体 dirent *pDir);
- void スキャンディレクトリと配布(void);
- void スリープ(UINT32 iCountMs);
-
-
- /****************************************************************
- * 機能説明: 主な機能
- * 入力パラメータ: なし
- * 出力パラメータ: なし
- * 戻り値: 0 - 実行完了
- * その他の指示: なし
- * 変更日 バージョン番号 修正者 変更内容
- *
- * 20160517 V1.0 作成者: Zhou Zhaoxiong
- ************************************************************************/
- INT32メイン(void)
- {
- // ソースファイルのディレクトリ
- snprintf(g_szSourceDir, sizeof(g_szSourceDir)-1, "%s/zhouzx/TestDir/SourceDir" , getenv( "HOME" ));
-
- //ファイル配布を実行する関数を呼び出す
- (1)
- {
- スキャンディレクトリと配布();
-
- Sleep(60 * 1000); // 1分ごとにファイルを配布する
- }
-
- 0を返します。
- }
-
-
- /******************************************************************************************
- * 機能の説明: 拡張子に基づいてファイルを選択
- * 入力パラメータ: dir-ディレクトリ
- * 出力パラメータ: なし
- * 戻り値: 0-失敗、1-成功
- * その他の指示: test.txt のようなファイルはスキャン対象ですが、test のようなファイルは条件を満たしていません。
- * 変更日 バージョン番号 修正者 変更内容
- *
- * 20160517 V1.0 作成者: ZhouZhaoxiong
- ******************************************************************************/
- INT32 SelectFlies(構造体 dirent *pDir)
- {
- (pDir == NULL )の場合
- {
- printf( "SelectFlies:入力パラメータがNULLです!\n" );
- 0を返します。
- }
-
- // .txt (サフィックス) に基づいてファイルを選択する
- (strstr(pDir->d_name, ".txt" ) != NULL の場合)
- {
- return 1; // 条件を満たすファイルが見つかりました
- }
- それ以外
- {
- 0を返します。
- }
- }
-
-
- /******************************************************************************************
- * 機能の説明: ディレクトリをスキャンしてファイルを配布する
- * 入力パラメータ: なし
- * 出力パラメータ: なし
- * 戻り値: なし
- * その他の指示: なし
- * 変更日 バージョン番号 修正者 変更内容
- *
- * 20160517 V1.0 作成者: ZhouZhaoxiong
- ******************************************************************************/
- void スキャンディレクトリと配布(void)
- {
- INT32 iScanDirRet = 0;
- UINT32 iFileIdx = 0;
- UINT32 iFileCount = 0;
- UINT32 iFileSize = 0;
- UINT8 szFileDir[256] = {0};
- UINT8 szScanedFile[512] = {0};
- UINT8 szCmdBuf[256] = {0};
- ファイル *fp = NULL ;
- 構造体 dirent **ppDirEnt = NULL ;
-
- // ソースディレクトリをスキャンしてファイルを配布する
- iScanDirRet = scandir(g_szSourceDir、&ppDirEnt、SelectFlies、alphasort);
- if (iScanDirRet < 0) // ディレクトリのスキャン中にエラーが発生しました
- {
- printf( "ScanDirAndDistribute:exec scandir に失敗しました。パス=%s\n" , g_szSourceDir);
- 戻る;
- }
- else if (iScanDirRet == 0) // ディレクトリにファイルがありません
- {
- printf( "ScanDirAndDistribute:ディレクトリ%sに条件に合うファイルがありません\n" , g_szSourceDir);
- }
- else // 条件を満たすファイルを対応するディレクトリに移動する
- {
- (iFileIdx = 0; iFileIdx < iScanDirRet; iFileIdx ++)の場合
- {
- // まずスキャンしたファイルが空ファイルかどうかを判断し、空ファイルの場合は直接削除し、空ファイルでない場合は移動操作を実行します
- memset(szScanedFile, 0x00, sizeof(szScanedFile));
- snprintf(szScanedFile, sizeof(szScanedFile) - 1, "%s/%s" , g_szSourceDir, ppDirEnt[iFileIdx]->d_name);
- fp = fopen(szScanedFile, "r" );
- if (fp == NULL ) // ファイルを開けなかった場合は直接戻ります
- {
- printf( "ScanDirAndDistribute:ファイル %s のオープンに失敗しました。確認してください!\n" , szScanedFile);
- 戻る;
- }
- fseek(fp, 0, SEEK_END);
- ファイルサイズ = ftell(fp);
- if (iFileSize == 0) // ファイルは空のファイルです
- {
- printf( "ScanDirAndDistribute:%s は空のファイルなので、直接削除してください!\n" , szScanedFile);
- memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
- snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "rm %s" , szScanedFile);
- システム(szCmdBuf);
- }
- else // プレフィックスに従って対応するディレクトリにファイルを移動(配布)します
- {
- if (strncmp(ppDirEnt[iFileIdx]->d_name, "File1_" , strlen( "File1_" )) == 0) // FileDir1 に移動
- {
- memset(szFileDir, 0x00, sizeof(szFileDir));
- snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir1" , getenv( "HOME" ));
- }
- else if (strncmp(ppDirEnt[iFileIdx]->d_name, "File2_" , strlen( "File2_" )) == 0) // FileDir2 に移動する
- {
- memset(szFileDir, 0x00, sizeof(szFileDir));
- snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir2" , getenv( "HOME" ));
- }
- else if (strncmp(ppDirEnt[iFileIdx]->d_name, "File3_" , strlen( "File3_" )) == 0) // FileDir3 に移動
- {
- memset(szFileDir, 0x00, sizeof(szFileDir));
- snprintf(szFileDir, sizeof(szFileDir)-1, "%s/zhouzx/TestDir/FileDir3" , getenv( "HOME" ));
- }
- else // プレフィックスが満たされていない場合は、ファイルを削除するだけです
- {
- memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
- snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "rm %s" , szScanedFile);
- システム(szCmdBuf);
-
- printf( "ScanDirAndDistribute:now, %s\n" , szCmdBuf);
-
- continue ; //次の判定を続ける
- }
-
- memset(szCmdBuf, 0x00, sizeof(szCmdBuf));
- snprintf(szCmdBuf, sizeof(szCmdBuf) - 1, "mv %s %s" , szScanedFile, szFileDir);
- システム(szCmdBuf);
-
- printf( "ScanDirAndDistribute:now, %s\n" , szCmdBuf);
-
- ファイルカウント++;
- }
- }
- }
-
- printf( "ScanDirAndDistribute: 今回は合計 %d 個のファイルを移動しました。\n" , iFileCount);
-
- 戻る;
- }
-
-
- /******************************************************************************************
- * 機能説明: プログラム休止状態
- * 入力パラメータ: iCountMs - スリープ時間 (単位: ms)
- * 出力パラメータ: なし
- * 戻り値: なし
- * その他の指示: なし
- * 変更日 バージョン番号 修正者 変更内容
- *
- * 20160517 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. プログラムのテスト 作成したプログラム「FileDistribute.c」を Linux マシンにアップロードし、「gcc -g -o FileDistribute FileDistribute.c」コマンドを使用してプログラムをコンパイルし、「FileDistribute」ファイルを生成します。以下はプログラムの詳細なテストです。 1. プログラムを起動する前に、File1_1.txt、File2_1.txt、File3_1.txt をソース ディレクトリ SourceDir に配置します。プログラムは次のように実行されます。 - ScanDirAndDistribute:今、mv /home/zhou/zhouzx/TestDir/SourceDir/File1_1.txt /home/zhou/zhouzx/TestDir/FileDir1
- ScanDirAndDistribute:now、mv /home/zhou/zhouzx/TestDir/SourceDir/File2_1.txt /home/zhou/zhouzx/TestDir/FileDir2
- ScanDirAndDistribute:now、mv /home/zhou/zhouzx/TestDir/SourceDir/File3_1.txt /home/zhou/zhouzx/TestDir/FileDir3
- ScanDirAndDistribute:今回は合計 3 つのファイルを移動しました。
ご覧のとおり、ソース ディレクトリ内の 3 つのファイルは存在しなくなりました。これらは、それぞれ結果ディレクトリ FileDir1、FileDir2、FileDir3 に移動されました。 - ~/zhouzx/TestDir/SourceDir>ll
- 合計 0
-
- ~/zhouzx/TestDir/FileDir1>ll
- -rw
-
- ~/zhouzx/TestDir/FileDir2>ll
- -rw
-
- ~/zhouzx/TestDir/FileDir3>ll
- -rw
2. しばらくしてから、File4_1.txt ファイルをソース ディレクトリ SourceDir に置くと、プログラムは次のように実行されます。 - ScanDirAndDistribute:今、rm /home/zhou/zhouzx/TestDir/SourceDir/File4_1.txt
- ScanDirAndDistribute:今回は合計 0 個のファイルを移動しました。1212
プレフィックスが一致しなかったため、File4_1.txt ファイルが直接削除されたことがわかります。 - ~/zhouzx/TestDir/SourceDir>ll
- 合計 01212
3. しばらくしてから、空のファイル File_7.txt、File_8.txt、File_9.txt をソース ディレクトリ SourceDir に配置すると、プログラムは次のように実行されます。 - ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_7.txtは空のファイルなので、直接削除してください。
- ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_8.txt は空のファイルなので、直接削除してください。
- ScanDirAndDistribute:/home/zhou/zhouzx/TestDir/SourceDir/File_9.txt は空のファイルなので、直接削除してください。
- ScanDirAndDistribute:今回は合計 0 個のファイルを移動しました。
ソースディレクトリ SourceDir 内のすべての空のファイルが削除されたことがわかります。 - ~/zhouzx/TestDir/SourceDir>ll
- 合計 01212
6. 需要拡大 この記事の要件と手順に基づいて、要件に対する次の拡張を検討できます。 1. ファイルを移動 (配布) する前に、まず対応する結果ディレクトリに同じファイル名のファイルが存在するかどうかを確認します。存在する場合は、ソース ディレクトリ内のファイルを直接削除します。存在しない場合は、ファイルを対応する結果ディレクトリに移動します。 2. 結果ディレクトリ内のファイルが多すぎるのを避けるために、プログラムにクリーンアップ メカニズムを追加して、一定期間以上保存されているファイルを削除することができます。 3. プログラムの柔軟性を反映するために、一部のファイル情報(ファイルのプレフィックス、サフィックス、保存ディレクトリ、スキャン間隔など)を設定ファイルに保存できます。プログラムが起動すると、関連する設定項目の値が読み取られ、後続のディレクトリスキャンとファイル配布操作が実行されます。 [この記事は51CTOコラムニストの周兆雄氏によるオリジナル記事です。著者のWeChat公開アカウント:周の論理(logiczhou)] この著者の他の記事を読むにはここをクリックしてください |