Linux中國

如何編寫 C 程序在 Linux 上創建音樂播放列表

使用我在 Linux 上製作的這個 C 程序在旅途中聆聽你喜愛的歌曲

我最近在 Linux 中編寫了一個 C 程序,從我廣泛的 MP3 庫中創建一個較小的隨機 MP3 文件選集。該程序會遍歷一個包含我的 MP3 庫的目錄,然後創建一個包含隨機的、較小的歌曲選集的目錄。然後我將這些 MP3 文件複製到我的智能手機上,以便隨時隨地收聽。

瑞典是一個人口稀少的國家,有許多農村地區沒有完整的手機覆蓋。這就是在智能手機上擁有 MP3 文件的原因之一。另一個原因是我並不總是有錢購買流媒體服務,所以我喜歡擁有自己喜歡的歌曲的副本。

你可以從它的 Git 倉庫 下載我的應用。我專門為 Linux 編寫了它,部分原因是在 Linux 上很容易找到經過良好測試的文件 I/O 常式。多年前,我嘗試使用專有的 C 庫在 Windows 上編寫相同的程序,但在嘗試文件複製時遇到了困難。Linux 使用戶可以輕鬆直接地訪問文件系統。

本著開源的精神,我沒費多少力氣就找到了 Linux 的文件 I/O 代碼來激發我的靈感。我還發現了一些啟發了我的分配內存的代碼。我編寫了隨機數生成的代碼。

該程序的工作方式如下所述:

  1. 詢問源目錄和目標目錄。
  2. 詢問存放 MP3 文件的目錄下的文件個數。
  3. 搜索你希望複製的收藏的百分比(從 1.0% 到 88.0%)。如果你有 1000 個文件的集合,並希望從你的集合中複製 125 個文件而不是 120 個文件,你也可以輸入 12.5% 之類的數字。我將上限設置為 88%,因為複製超過 88% 的庫將基本生成與你的基礎庫相似的庫。當然,代碼是開源的,因此你可以根據自己的喜好自由修改。
  4. 使用指針和 malloc 分配內存。一些操作需要內存,包括代表音樂收藏中文件的字元串列表。還有一個列表來保存隨機生成的數字。
  5. 生成所有文件範圍內的隨機數列表(例如,如果集合有 1000 個文件,則為 1 到 1000)。
  6. 複製文件。

其中一些部分比其他部分更簡單,但代碼只有大約 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] != &apos;.&apos;) {
        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

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國