这里使用两种处理方式,大体方法一致都是随机文件行号映射对应名字,核心处理方式不同。一种是行号排序后遍历文件读出名字;一种是读取文件,将每个名字存放到数组中,再随机生成名单。当数据量较大时,第二种比较占用内存,但执行效率高一些。
方式1
- 输入数据:文件名,要点的人数
- 遍历文件获取行号
- 遍历生成不重复的随机数存放在数组中
- 读取文件通过数组中的排序后的行号输出对应名字。
废话不多说,直接上代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<time.h>
#include<stdbool.h>
int getFileLines(char *filePath){
FILE *fp;
int fileline,count;
int flag;
fileline=count=0;
if((fp = fopen(filePath,"r+")) == NULL)
{
fprintf(stderr,"open file error! %s\n",strerror(errno));
}
while((flag = fgetc(fp)) != EOF)
{
if(flag == '\n')
{
count++;
}
}
fileline=count+1;
fclose(fp);
return fileline;
}
bool isContainsNum(int num, int *nums, int numsSize)
{
for (int i=0; i < numsSize; i++)
{
if (num == nums[i])
return true;
}
return false;
}
int cmp_int(const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
void readlines(int *lines, int size, char *filePath){
FILE *fp;
int index=0;
int CurrentIndex = 0;
qsort(lines,size,sizeof(lines[0]),cmp_int);
char StrLine[20]={0};
if((fp = fopen(filePath,"r+")) == NULL)
{
fprintf(stderr,"open file error! %s\n",strerror(errno));
}
while (!feof(fp))
{
fgets(StrLine,20,fp);
CurrentIndex++;
if (CurrentIndex==lines[index])
{
if(index>size)
break;
printf("%s", StrLine);
index++;
memset(StrLine,0,sizeof(StrLine));
}
memset(StrLine,0,sizeof(StrLine));
}
fclose(fp);
}
int main(int argc, char *argv[])
{
char *pfile,file[50]={0};
pfile=file;
int lines=0;
int n,i=0,nums=0;
int index[1000]={0};
puts("请输入txt名单文件:");
scanf("%s",file);
puts("请输入要点的人数:");
scanf("%d",&nums);
printf("文件:%s\n",pfile);
lines=getFileLines(pfile);
printf("名单人数:%d\n",lines);
if(nums>lines){
printf("点名人数大于总人数,请重试!");
return -1;
}
srand((unsigned)time(NULL));
while (1)
{
n=rand()%lines + 1;
if(i==0){
index[0]=n;
i++;
}
else{
if(!isContainsNum(n,index,i)){
index[i]=n;
i++;
}
}
if(i==nums)
break;
}
puts("\n随机点中的名单:");
readlines(index,nums,pfile);
pfile=NULL;
return 0;
}
方式2
- 输入数据:文件名,要点的人数
- 遍历文件获取行号,同时将每个名字存放到数组中
- 遍历生成不重复的随机数存放在数组中
- 直接输出下标数组中对应名字
废话不多说,直接上代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<time.h>
#include<stdbool.h>
int getFileLines(char *filePath, char arrName[][20]){
FILE *fp;
int count=0;
int flag;
char StrLine[20]={0};
if((fp = fopen(filePath,"r+")) == NULL)
{
fprintf(stderr,"open file error! %s\n",strerror(errno));
}
while (!feof(fp))
{
fgets(StrLine,20,fp);
strcpy(arrName[count],StrLine);
count++;
}
puts("\n");
fclose(fp);
return count;
}
bool isContainsNum(int num, int *nums, int numsSize)
{
for (int i=0; i < numsSize; i++)
{
if (num == nums[i])
return true;
}
return false;
}
int main(int argc, char *argv[])
{
char *pfile,file[50]={0};
pfile=file;
int lines=0;
int n,i=0,nums=0;
char arrName[1000][20]={0};
int index[1000]={0};
puts("请输入txt名单文件:");
scanf("%s",file);
puts("请输入要点的人数:");
scanf("%d",&nums);
printf("文件:%s",pfile);
lines=getFileLines(pfile,arrName);
printf("名单人数:%d\n",lines);
if(nums>lines){
printf("点名人数大于总人数,请重试!");
return -1;
}
srand((unsigned)time(NULL));
while (1)
{
n=rand()%lines;
if(i==0){
index[0]=n;
i++;
}
else{
if(!isContainsNum(n,index,i)){
index[i]=n;
i++;
}
}
if(i==nums)
break;
}
puts("\n随机点中的名单:");
for(int i=0; i<nums; i++){
printf("%s",arrName[index[i]]);
}
pfile=NULL;
return 0;
}
运行结果: 此处使用VSCode 注意: 在win终端cmd运行,避免中文乱码,需要将源码及名单文件转为gb2312编码,使用Notepad++转为ASNI编码
最后代码有什么不足或可以改善地方,请大家积极发言,不胜感激。
|