如何在 Linux 上创建音乐播放列表

使用我在 Linux 上制作的这个 C 程序,随时随地收听您喜爱的歌曲。
4 位读者喜欢这篇文章。
music infinity

Opensource.com

我最近在 Linux 中编写了一个 C 程序,用于从我庞大的 MP3 库中创建较小的随机 MP3 文件选择。该程序遍历包含我的 MP3 库的目录,然后创建一个包含随机、较小的歌曲选择的目录。然后,我将 MP3 文件复制到我的智能手机上,以便随时随地收听。

瑞典是一个人口稀少的国家,有许多农村地区没有完整的手机信号覆盖。这是在智能手机上拥有 MP3 文件的原因之一。另一个原因是,我并不总是有钱购买流媒体服务,所以我喜欢拥有自己喜欢的歌曲的副本。

您可以从我的 Git 仓库 下载我的应用程序。我专门为 Linux 编写了它,部分原因是很容易在 Linux 上找到经过良好测试的文件 I/O 例程。多年前,我尝试在 Windows 上使用专有的 C 库编写相同的程序,结果在尝试让文件复制例程工作时遇到了困难。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 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 编程语言的简单效率。

User profile image.
大家好,我叫 Richard,是一名患有 ADHD 和阿斯伯格综合症的中级 Linux 用户。

4 条评论

嗨 Rikard,

我也不经常流式传输,主要是因为它会更快地耗尽电池电量。

这是我的 bash 脚本版本

# 配置部分
procFilesCopy=50;
from=/path/to/my/music/collection;
to=/path/to/phone/mount;

# 执行部分
fileCount=$(ls $from | wc -l);
copyCount=$(($fileCount * $procFilesCopy / 100));
ls $from | shuf -n $copyCount | while read f; do cp $from/$f $to; done

非常有帮助,谢谢!

嘿 Rickard,
我想知道如何为 mp4 格式实现这一点,
谢谢。

实际上非常简单。
只需下载代码。
在所有找到字符串“.mp3”的地方,您只需将其替换为“.mp4”或您喜欢的任何其他文件扩展名即可:)

此致 Richard

回复 作者 RUTIK PATIL

Creative Commons License本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.