我最近在 Linux 中编写了一个 C 程序,用于从我庞大的 MP3 库中创建一个较小的随机 MP3 文件选择。该程序遍历包含我的 MP3 库的目录,然后创建一个包含随机、较小歌曲选择的目录。然后我将 MP3 文件复制到我的智能手机上,以便随时随地收听。
瑞典是一个人口稀少的国家,有许多农村地区没有完整的手机信号覆盖。这是在智能手机上拥有 MP3 文件的原因之一。另一个原因是,我并不总是有钱购买流媒体服务,所以我喜欢拥有自己喜欢的歌曲的副本。
您可以从其 Git 存储库下载我的应用程序。我专门为 Linux 编写它,部分原因是很容易在 Linux 上找到经过良好测试的文件 I/O 例程。 多年前,我尝试使用专有的 C 库在 Windows 上编写相同的程序,但我卡在让文件复制例程工作上。 Linux 允许用户轻松直接地访问文件系统。
本着开源的精神,我很快就找到了 Linux 的文件 I/O 代码来启发我。我还找到了一些用于分配内存的代码来启发我。我编写了用于生成随机数的代码。
该程序的工作方式如下:
- 它会询问源目录和目标目录。
- 它会询问 MP3 文件目录中的文件数量。
- 它会搜索您希望复制的集合的百分比(从 1.0% 到 88.0%)。如果您有 1000 个文件并希望从集合中复制 125 个文件而不是 120 个文件,您也可以输入像 12.5% 这样的数字。 我将上限设置为 88%,因为复制超过 88% 的库主要会生成与您的基本集合类似的集合。 当然,该代码是开源的,因此您可以随意修改它以符合您的喜好。
- 它使用指针和 malloc 分配内存。 内存是多个操作所必需的,包括表示音乐收藏中文件的字符串列表。 还有一个列表用于保存随机生成的数字。
- 它生成一个随机数列表,范围是所有文件(例如,如果集合有 1000 个文件,则为 1 到 1000)。
- 它复制文件。
其中一些部分比其他部分更简单,但代码只有大约 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 编程语言的简单效率。
4 条评论