如何編寫 C 程序在 Linux 上創建音樂播放列表
使用我在 Linux 上製作的這個 C 程序在旅途中聆聽你喜愛的歌曲。
我最近在 Linux 中編寫了一個 C 程序,從我廣泛的 MP3 庫中創建一個較小的隨機 MP3 文件選集。該程序會遍歷一個包含我的 MP3 庫的目錄,然後創建一個包含隨機的、較小的歌曲選集的目錄。然後我將這些 MP3 文件複製到我的智能手機上,以便隨時隨地收聽。
瑞典是一個人口稀少的國家,有許多農村地區沒有完整的手機覆蓋。這就是在智能手機上擁有 MP3 文件的原因之一。另一個原因是我並不總是有錢購買流媒體服務,所以我喜歡擁有自己喜歡的歌曲的副本。
你可以從它的 Git 倉庫 下載我的應用。我專門為 Linux 編寫了它,部分原因是在 Linux 上很容易找到經過良好測試的文件 I/O 常式。多年前,我嘗試使用專有的 C 庫在 Windows 上編寫相同的程序,但在嘗試文件複製時遇到了困難。Linux 使用戶可以輕鬆直接地訪問文件系統。
本著開源的精神,我沒費多少力氣就找到了 Linux 的文件 I/O 代碼來激發我的靈感。我還發現了一些啟發了我的分配內存的代碼。我編寫了隨機數生成的代碼。
該程序的工作方式如下所述:
- 詢問源目錄和目標目錄。
- 詢問存放 MP3 文件的目錄下的文件個數。
- 搜索你希望複製的收藏的百分比(從 1.0% 到 88.0%)。如果你有 1000 個文件的集合,並希望從你的集合中複製 125 個文件而不是 120 個文件,你也可以輸入 12.5% 之類的數字。我將上限設置為 88%,因為複製超過 88% 的庫將基本生成與你的基礎庫相似的庫。當然,代碼是開源的,因此你可以根據自己的喜好自由修改。
- 使用指針和
malloc
分配內存。一些操作需要內存,包括代表音樂收藏中文件的字元串列表。還有一個列表來保存隨機生成的數字。 - 生成所有文件範圍內的隨機數列表(例如,如果集合有 1000 個文件,則為 1 到 1000)。
- 複製文件。
其中一些部分比其他部分更簡單,但代碼只有大約 100 行:
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* include necessary header files */
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#define BUF_SIZE 4096 /* use buffer of 4096 bytes */
#define OUTPUT_MODE 0700 /*protect output file */
#define MAX_STR_LEN 256
int main(void) {
DIR *d;
struct dirent *dir;
char strTemp[256], srcFile[256],
dstFile[256], srcDir[256], dstDir[256];
char **ptrFileLst;
char buffer[BUF_SIZE];
int nrOfStrs=-1, srcFileDesc,
dstFileDesc, readByteCount,
writeByteCount, numFiles;
int indPtrFileAcc, q;
float nrFilesCopy;
// vars for generatingRandNumList
int i, k, curRanNum, curLstInd,
numFound, numsToGen, largNumRange;
int *numLst;
float procFilesCopy;
printf("Enter name of source Directoryn");
scanf("%s", srcDir);
printf("Enter name of destionation Directoryn");
scanf("%s", dstDir);
printf("How many files does the directory with mp3 files contain?n");
scanf("%d", &numFiles);
printf("What percent of the files do you wish to make a random selection ofn");
printf("enter a number between 1 and 88n");
scanf("%f", &procFilesCopy);
// allocate memory for filesList, list of random numbers
ptrFileLst= (char**) malloc(numFiles * sizeof(char*));
for (i = 0; i < numFiles; i++) {
ptrFileLst[i] = (char*)malloc(MAX_STR_LEN * sizeof(char));
}
largNumRange = numFiles;
nrFilesCopy = (procFilesCopy / 100) * numFiles;
numsToGen = (int)((procFilesCopy / 100) * numFiles);
printf("nrFilesCopy=%f", nrFilesCopy);
printf("NumsToGen=%d", numsToGen);
numLst = malloc(numsToGen * sizeof(int));
srand(time(0));
numLst[0] = rand() % largNumRange + 1;
numFound=0;
do {
curRanNum = (int)rand() % largNumRange + 1;
if (numLst[0] == curRanNum) {
numFound=1;
}
} while(numFound == 1);
numLst[1] = curRanNum;
getchar();
curLstInd = 1;
i = 0;
while(1) {
do {
numFound = 0;
curRanNum = (int)rand() % largNumRange + 1;
for (int k = 0; k <= curLstInd; k++){
if (numLst[k] == curRanNum)
numFound = 1;
}
} while(numFound == 1);
numLst[curLstInd+1] = curRanNum;
curLstInd++;
i++;
// numsToGen=Total numbers to generate minus two
// already generated by the code above this loop
if (i == (numsToGen-2))
break;
}
d = opendir(srcDir);
if (d) {
while ( (dir = readdir(d)) != NULL ) {
strcpy(strTemp, dir->d_name);
if (strTemp[0] != '.') {
nrOfStrs++;
strcpy(ptrFileLst[nrOfStrs], strTemp);
}
}
closedir(d);
}
for (q = 0; q <= curLstInd; q++) {
indPtrFileAcc = numLst[q];
strcpy(srcFile, srcDir);
strcat(srcFile, "/");
strcat(srcFile, ptrFileLst[indPtrFileAcc]);
strcpy(dstFile, dstDir);
strcat(dstFile, "/");
strcat(dstFile, ptrFileLst[indPtrFileAcc]);
srcFileDesc = open(srcFile, O_RDONLY);
dstFileDesc = creat(dstFile, OUTPUT_MODE);
while(1) {
readByteCount = read(srcFileDesc, buffer, BUF_SIZE);
if (readByteCount <= 0)
break;
writeByteCount = write(dstFileDesc, buffer, readByteCount);
if(writeByteCount <= 0)
exit(4);
}
//close the files
close(srcFileDesc);
close(dstFileDesc);
}
}
這段代碼可能是最複雜的:
while(1) {
readByteCount = read(srcFileDesc, buffer, BUF_SIZE);
if (readByteCount <= 0)
break;
writeByteCount = write(dstFileDesc, buffer, readByteCount);
if (writeByteCount <= 0)
exit(4);
}
這將從指定的文件中讀取多個位元組(readByteCount
)到字元緩衝區中。該函數的第一個參數是文件名(srcFileDesc
)。第二個參數是一個指向字元緩衝區的指針,這之前在程序中聲明過。該函數的最後一個參數是緩衝區的大小。
程序返回讀取的位元組數(在本例中為 4 個位元組)。如果返回的數字為 0 或更少,則第一個 if
子句會跳出循環。
如果讀取位元組數為 0,則所有寫入完成,循環中斷以寫入下一個文件。如果讀取的位元組數小於 0,則發生錯誤並退出程序。
當讀取 4 個位元組時,它會寫入它們。write
函數接受三個參數。第一個是要寫入的文件,第二個是字元緩衝區,第三個是要寫入的位元組數(4 個位元組) .該函數返回寫入的位元組數。
如果寫入了 0 個位元組,則發生了寫入錯誤,因此第二個 if
子句退出程序。
while
循環讀取並複製文件,一次 4 個位元組,直到文件被複制。複製完成後,你可以將隨機生成的 mp3 文件的目錄複製到你的智能手機。
複製和寫入常式相當有效,因為它們使用 Linux 中的文件系統調用。
改進代碼
該程序很簡單,可以在用戶界面和靈活性方面進行改進。例如,你可以實現一個計算源目錄中文件數量的函數,這樣你就不必手動輸入它。你可以添加選項,這樣你就可以非交互地傳遞百分比和路徑。但是代碼做了我需要它做的事情,它是 C 編程語言簡單效率的演示。
via: https://opensource.com/article/22/7/c-linux-mp3
作者:Rikard Grossman-Nielsen 選題:lkxed 譯者:geekpi 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive