如何编写 C 程序在 Linux 上创建音乐播放列表
创始人
2024-03-02 11:50:40
0

使用我在 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 
#include 
#include 
#include  /* include necessary header files */
#include 
#include 
#include 
#include 

#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 Directory\n");
  scanf("%s", srcDir);
  printf("Enter name of destionation Directory\n");
  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 of\n");
  printf("enter a number between 1 and 88\n");
  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

本文由 LCTT 原创编译,Linux中国 荣誉推出

相关内容

父亲节也要仪式感!我们请A...
又是一年父亲节,我们用AI给父亲们写了一首专属歌曲,祝每一位默默付...
2025-06-15 08:12:30
随着热门歌曲跳舞,“出演”...
【环球时报驻法国、美国特派特约记者 尚凯元 冯亚仁 文远】由法国、...
2025-02-11 07:43:13
不要让下一首歌曲从播放列表...
下面是一个示例代码,演示如何实现在播放列表中不移除上一首歌曲:cl...
2025-01-10 21:01:20
不加载完整歌曲的情况下制作...
要制作音频精灵(Audio Sprite)且不加载完整歌曲的情况下...
2024-12-25 20:02:14
播放已下载到缓存目录的歌曲
要播放已下载到缓存目录的歌曲,你可以使用Android中的Medi...
2024-12-23 10:01:15
播放/暂停按钮在播放歌曲时...
你可以使用一个变量来追踪当前的播放状态,然后在更新播放/暂停按钮时...
2024-12-23 08:01:31

热门资讯

Helix:高级 Linux ... 说到 基于终端的文本编辑器,通常 Vim、Emacs 和 Nano 受到了关注。这并不意味着没有其他...
使用 KRAWL 扫描 Kub... 用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。当你使用 Kubernet...
JStock:Linux 上不... 如果你在股票市场做投资,那么你可能非常清楚投资组合管理计划有多重要。管理投资组合的目标是依据你能承受...
通过 SaltStack 管理... 我在搜索Puppet的替代品时,偶然间碰到了Salt。我喜欢puppet,但是我又爱上Salt了:)...
Epic 游戏商店现在可在 S... 现在可以在 Steam Deck 上运行 Epic 游戏商店了,几乎无懈可击! 但是,它是非官方的。...
《Apex 英雄》正式可在 S... 《Apex 英雄》现已通过 Steam Deck 验证,这使其成为支持 Linux 的顶级多人游戏之...
如何在 Github 上创建一... 学习如何复刻一个仓库,进行更改,并要求维护人员审查并合并它。你知道如何使用 git 了,你有一个 G...
2024 开年,LLUG 和你... Hi,Linuxer,2024 新年伊始,不知道你是否已经准备好迎接新的一年~ 2024 年,Lin...
什么是 KDE Connect... 什么是 KDE Connect?它的主要特性是什么?它应该如何安装?本文提供了基本的使用指南。科技日...
Opera 浏览器内置的 VP... 昨天我们报道过 Opera 浏览器内置了 VPN 服务,用户打开它可以防止他们的在线活动被窥视。不过...