---
author: Rikard Grossman-nielsen
category: 软件开发
comments_data:
- date: '2022-07-28 16:02:25'
  message: 啊。。。。这。。。。。。。
  postip: 221.224.214.38
  username: 来自江苏苏州的 Firefox 102.0|Ubuntu 用户
count:
  commentnum: 1
  favtimes: 0
  likes: 0
  sharetimes: 0
  viewnum: 2501
date: '2022-07-26 22:34:08'
editorchoice: false
excerpt: 使用我在 Linux 上制作的这个 C 程序在旅途中聆听你喜爱的歌曲。
fromurl: https://opensource.com/article/22/7/c-linux-mp3
id: 14868
islctt: true
largepic: /images/p/202207/26/223349t4yiqd1yikb9k117.jpg
permalink: /article-14868-1.html
pic: /images/p/202207/26/223349t4yiqd1yikb9k117.jpg.thumb.jpg
related: []
reviewer: wxy
selector: lkxed
summary: 使用我在 Linux 上制作的这个 C 程序在旅途中聆听你喜爱的歌曲。
tags:
- 歌曲
thumb: false
title: 如何编写 C 程序在 Linux 上创建音乐播放列表
titlepic: true
translator: geekpi
updated: '2022-07-26 22:34:08'
---

![](/images/p/202207/26/223349t4yiqd1yikb9k117.jpg)



> 
> 使用我在 Linux 上制作的这个 C 程序在旅途中聆听你喜爱的歌曲。
> 
> 
> 


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


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


你可以从它的 [Git 仓库](https://github.com/rikardgn/learnC/blob/main/randMp3Copy.c) 下载我的应用。我专门为 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 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](https://opensource.com/users/rikardgn) 选题：[lkxed](https://github.com/lkxed) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出