mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-23 21:20:42 +08:00
216 lines
8.3 KiB
Markdown
216 lines
8.3 KiB
Markdown
[#]: subject: "How I create music playlists on Linux"
|
||
[#]: via: "https://opensource.com/article/22/7/c-linux-mp3"
|
||
[#]: author: "Rikard Grossman-Nielsen https://opensource.com/users/rikardgn"
|
||
[#]: collector: "lkxed"
|
||
[#]: translator: "geekpi"
|
||
[#]: reviewer: "wxy"
|
||
[#]: publisher: "wxy"
|
||
[#]: url: "https://linux.cn/article-14868-1.html"
|
||
|
||
如何编写 C 程序在 Linux 上创建音乐播放列表
|
||
======
|
||
|
||
![](https://img.linux.net.cn/data/attachment/album/202207/26/223349t4yiqd1yikb9k117.jpg)
|
||
|
||
> 使用我在 Linux 上制作的这个 C 程序在旅途中聆听你喜爱的歌曲。
|
||
|
||
我最近在 Linux 中编写了一个 C 程序,从我广泛的 MP3 库中创建一个较小的随机 MP3 文件选集。该程序会遍历一个包含我的 MP3 库的目录,然后创建一个包含随机的、较小的歌曲选集的目录。然后我将这些 MP3 文件复制到我的智能手机上,以便随时随地收听。
|
||
|
||
瑞典是一个人口稀少的国家,有许多农村地区没有完整的手机覆盖。这就是在智能手机上拥有 MP3 文件的原因之一。另一个原因是我并不总是有钱购买流媒体服务,所以我喜欢拥有自己喜欢的歌曲的副本。
|
||
|
||
你可以从它的 [Git 仓库][2] 下载我的应用。我专门为 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][a]
|
||
选题:[lkxed][b]
|
||
译者:[geekpi](https://github.com/geekpi)
|
||
校对:[wxy](https://github.com/wxy)
|
||
|
||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||
|
||
[a]: https://opensource.com/users/rikardgn
|
||
[b]: https://github.com/lkxed
|
||
[1]: https://opensource.com/sites/default/files/lead-images/LIFE_musicinfinity.png
|
||
[2]: https://github.com/rikardgn/learnC/blob/main/randMp3Copy.c
|