操作系统第三次实验报告

合集下载

操作系统实验报告3

操作系统实验报告3

操作系统实验报告3一、实验目的本次操作系统实验的主要目的是深入了解和掌握操作系统中进程管理、内存管理以及文件系统等核心概念和相关技术,并通过实际的实验操作,提高对操作系统原理的理解和应用能力。

二、实验环境本次实验使用的操作系统为 Windows 10,开发工具为 Visual Studio 2019。

三、实验内容及步骤(一)进程管理实验1、创建进程使用 C++语言编写程序,通过调用 Windows API 函数`CreateProcess`来创建一个新的进程。

在创建进程时,设置进程的优先级、环境变量等参数,并观察进程的创建过程和相关的系统资源使用情况。

```cppinclude <windowsh>include <iostream>int main(){STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(&si, sizeof(si));sicb = sizeof(si);ZeroMemory(&pi, sizeof(pi));//设置进程的优先级为 HIGH_PRIORITY_CLASS DWORD priorityClass = HIGH_PRIORITY_CLASS;//创建进程if (!CreateProcess(NULL, //应用程序名称"notepadexe",//命令行参数NULL, //进程安全性NULL, //线程安全性FALSE, //不继承句柄priorityClass, //进程优先级NULL, //环境变量NULL, //当前目录&si,&pi)){std::cout <<"CreateProcess failed Error code: "<<GetLastError()<< std::endl;return 1;}//等待进程结束WaitForSingleObject(pihProcess, INFINITE);//关闭进程和线程的句柄CloseHandle(pihProcess);CloseHandle(pihThread);return 0;}```2、进程同步与互斥编写一个多线程程序,模拟生产者消费者问题。

操作系统实验报告三

操作系统实验报告三

操作系统实验报告三一、实验目的本次实验的目的是通过设计和实现一个简单的操作系统,加深对操作系统内核设计的理解,并学习操作系统内核的基本构建和运行原理。

二、实验背景操作系统是计算机系统中最核心的软件之一,它负责管理计算机的各种资源以及协调和控制应用程序的执行。

操作系统的设计和实现使计算机能够高效地运行并提供友好的用户接口。

操作系统也为应用程序提供了统一的软硬件访问接口,方便开发人员进行软件开发。

操作系统的设计和实现是计算机科学与技术领域中重要的研究方向之一。

通过操作系统的实验,可以深入了解操作系统的内部原理和机制,加深对操作系统的理解和认识。

三、实验内容本次实验需要设计和实现一个简单的操作系统,完成以下功能:1. 实现一个简单的内存管理模块,包括内存分配和释放的功能。

2. 实现一个简单的进程管理模块,包括进程的创建、撤销和切换的功能。

3. 实现一个简单的文件系统模块,包括文件的读写和目录的管理功能。

4. 实现用户与操作系统之间的交互界面,方便用户进行操作系统的使用。

四、实验步骤1. 设计和实现内存管理模块:a. 设计内存分配算法,根据系统的需要分配和释放内存空间。

b. 实现内存分配和释放的功能函数,确保能够正确地分配和释放内存空间。

2. 设计和实现进程管理模块:a. 设计进程控制块(PCB),记录进程的相关信息。

b. 实现进程的创建、撤销和切换的功能函数,确保进程能够正确地被创建、撤销和切换。

3. 设计和实现文件系统模块:a. 设计文件控制块(FCB),记录文件的相关信息。

b. 实现文件的读写和目录的管理功能函数,确保文件能够正确地被读写和目录能够正确地被管理。

4. 实现用户与操作系统之间的交互界面:a. 设计用户界面,包括命令解释器等。

b. 实现用户输入命令的解释和执行函数,确保用户能够正确地与操作系统进行交互。

五、实验结果与分析经过实验,我们成功地设计和实现了一个简单的操作系统,并完成了内存管理、进程管理和文件系统的功能实现。

哈工大《操作系统》实验3

哈工大《操作系统》实验3

向kernel/printk.c中添加日志打印功能,将以下代码添加到原文件中:
在kernel/fork.c、kernel/sched.c和kernel/exit.c中,找到正确的状态转换点,并添加合适的状态信息,把它输出到log文件之中。

fork.c的修改如下:
exit.c的修改如下:
sched.c的修改如下:
在虚拟机上运行ls -l /var”或“ll /var”查看process.log是否建立,及它的属性和长度;
修改时间片
include/linux/sched.h宏INIT_TASK中定义的:
0,15,15, 分别对应state、counter和priority,将priority值修改,即可实现对时间片大小的调整。

0,15,15, 分别对应state、counter和priority,
priority值修改,即可实现对时间片大小的调整。

在修改时间片将priority由15改为150后,Process 9~20 中Turnaround, Waiting, CPU Burst, I/O Burst变化不大,原因可能是程序中I/O操作占用的时间对于总时间影响的权重过大,导致处理时间体现的并不明显。

或者变化不大的原因是,子进程连续占用cpu的时间要比时间片大很多。

操作系统实验三实验报告

操作系统实验三实验报告
int i,j,pid;
//srand((unsigned)time(0));
printf("Ctrl-C让进程优先度加一,Ctrl-Z让进程优先度减一");
if((pid=fork())==0)
{
signal(SIGINT,(sighandler_t)sigcat_1);
signal(SIGTSTP,(sighandler_t)sigcat_2);
kill(getppid(),SIGINT);
}else{
printf("子进程发送SIGTSTP信号给父进程\n");
kill(getppid(),SIGTSTP);
}
pause(); */
sleep(1);
}
}else{
signal(SIGINT,(sighandler_t)sigcat_1);
// SIGTSTP停止进程的运行,但该信号可以被处理和忽略.用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号
typedef void (*sighandler_t) (int);
void sigcat_1(){
printf("SIGINT信号,优先度加一\n");
setpriority(PRIO_PROCESS,getpid(),getpriority(PRIO_PROCESS,getpid())+1);
略。进程初始调度策略均为系统默认策略和默认优先级。当某个进程收到SIGINT
信号时会自动将其优先数加1,收到SIGTSTP信号时会自动将其优先数减1。请编
程实现以上功能。
2.3实验的软硬件环境
Ubuntu14.04 intelPC

操作系统实验报告3

操作系统实验报告3

《操作系统》实验报告
实验序号:3 实验项目名称:作业调度的实现
return 0;
}
具体实现步骤:
1.将实验指导目录中linux下的os3中的src 放在桌面上。

2.打开终端1,输入以下指令:
【cd ./桌面/src】
【gcc job.c error.c –ojob】
【gcc enq.c error.c -oenq】
【gcc deq.c error.c -odeq】
【gcc stat.c error.c -ostat】
3.编写123.c和456.c两个死循环程序,编译运行无误,并改名生成程序P1,
P2。

4.执行./job &指令将p2添加到p1中。

5.打开终端2
输入【cd ./桌面/src】指令
执行【./stat】指令查看进程状态
反复调用【./stat】指令
6.交替执行指令【./enq】和【./deq】指令删除p1,p2并再次添加并调用【./stat】
指令查看进程变化。

7.实验完成后调用【kill】指令结束进程。

运行截图如下:。

操作系统实验三(页面置换算法)实验报告

操作系统实验三(页面置换算法)实验报告

实验三实验报告实验源码:#include "stdio.h"#include <iostream.h>#include <stdlib.h>#define DataMax 100 // 常量DataMax#define BlockNum 10 // 常量BlockNumint DataShow[BlockNum][DataMax]; // 用于存储要显示的数组bool DataShowEnable[BlockNum][DataMax]; // 用于存储数组中的数据是否需要显示int Data[DataMax]; // 保存数据int Block[BlockNum]; // 物理块int count[BlockNum]; // 计数器int N; // 页面个数int M; // 最小物理块数int ChangeTimes; // 缺页次数void DataInput(); // 输入数据的函数void DataOutput(); // 输出数据的函数void FIFO(); // FIFO 函数void Optimal(); // Optimal函数void LRU(); // LRU函数int main(int argc, char* argv[]){DataInput();int menu;while(true){printf("\n* 菜单选择*\n");printf("*******************************************************\n");printf("* 1-Optimal *\n");printf("* 2-FIFO *\n");printf("* 3-LRU *\n");printf("* 4-返回上一级*\n");printf("* 0-EXIT *\n");printf("*******************************************************\n");scanf("%d",&menu);switch(menu){case 1:Optimal();break;case 2:FIFO();break;case 3:LRU();break;case 0:exit(0);break;case 4:system("cls");DataInput();break;}if(menu != 1 && menu != 2 && menu != 3 && menu != 0 && menu !=4) { system("cls");printf("\n请输入0 - 4之间的整数!\n");continue;}}return 0;}void DataInput(){int i,choice;printf("请输入最小物理块数:");scanf("%d",&M);// 输入最小物理块数大于数据个数while(M > BlockNum){printf("物理块数超过预定值,请重新输入:");scanf("%d",&M);}printf("请输入页面的个数:");scanf("%d",&N);// 输入页面的个数大于数据个数while(N > DataMax){printf("页面个数超过预定值,请重新输入:");scanf("%d",&N);}printf("请选择产生页面访问序列的方式(1.随机2.输入):");scanf("%d",&choice);switch(choice){case 1:// 产生随机访问序列for(i = 0;i < N;i++){Data[i] = (int)(((float) rand() / 32767) * 10); // 随机数大小在0 - 9之间}system("cls");// 显示随机产生的访问序列printf("\n随机产生的访问序列为:");for(i = 0;i < N;i++){printf("%d ",Data[i]);}printf("\n");break;case 2:// 输入访问序列printf("请输入页面访问序列:\n");for(i = 0;i < N;i++)scanf("%d",&Data[i]);system("cls");// 显示输入的访问序列printf("\n输入的访问序列为:");for(i = 0;i < N;i++){printf("%d ",Data[i]);}printf("\n");break;default:while(choice != 1 && choice != 2){printf("请输入1或2选择相应方式:");scanf("%d",&choice);}break;}}void DataOutput(){int i,j;// 对所有数据操作for(i = 0;i < N;i++){printf("%d ",Data[i]);}printf("\n");for(j = 0;j < M;j++){// 对所有数据操作for(i = 0;i < N;i++){if( DataShowEnable[j][i] )printf("%d ",DataShow[j][i]);elseprintf(" ");}printf("\n");}printf("缺页次数: %d\n",ChangeTimes);printf("缺页率: %d %%\n",ChangeTimes * 100 / N); }// 最佳置换算法void Optimal(){int i,j,k;bool find;int point;int temp; // 临时变量,比较离的最远的时候用int m = 1,n;ChangeTimes = 0;for(j = 0;j < M;j++){for(i=0;i < N;i++){DataShowEnable[j][i] = false; // 初始化为false,表示没有要显示的数据}}for(i = 0;i < M;i++){count[i] = 0 ; // 初始化计数器}// 确定当前页面是否在物理块中,在继续,不在置换/////////////////////////////////////////////////////////////////////////////////// Block[0] = Data[0];for(i = 1;m < M;i++){int flag = 1;for(n = 0; n < m;n++){if(Data[i] == Block[n]) flag = 0;}if(flag == 0) continue;Block[m] = Data[i];m++;}//////////////////////////////////////////////////////////////////////////////////// 对所有数据进行操作for(i=0;i < N;i++){// 表示块中有没有该数据find = false;for(j = 0;j < M;j++){if( Block[j] == Data[i] ){find = true;}}if( find ) continue; // 块中有该数据,判断下一个数据// 块中没有该数据,最优算法ChangeTimes++; // 缺页次数++for(j = 0;j < M;j++){// 找到下一个值的位置find = false;for( k = i;k < N;k++){if( Block[j] == Data[k] ){find = true;count[j] = k;break;}}if( !find ) count[j] = N;}// 因为i是从0开始记,而BlockNum指的是个数,从1开始,所以i+1if( (i + 1) > M ){//获得要替换的块指针temp = 0;for(j = 0;j < M;j++){if( temp < count[j] ){temp = count[j];point = j; // 获得离的最远的指针}}}else point = i;// 替换Block[point] = Data[i];// 保存要显示的数据for(j = 0;j < M;j++){DataShow[j][i] = Block[j];DataShowEnable[i < M ? (j <= i ? j : i) : j][i] = true; // 设置显示数据}}// 输出信息printf("\nOptimal => \n");DataOutput();}// 先进先出置换算法void FIFO(){bool find;int point;int temp; // 临时变量int m = 1,n;ChangeTimes = 0;for(j = 0;j < M;j++){for(i = 0;i < N;i++){DataShowEnable[j][i] = false; // 初始化为false,表示没有要显示的数据}}for(i = 0;i < M;i++){count[i] = 0; // 大于等于BlockNum,表示块中没有数据,或需被替换掉// 所以经这样初始化(3 2 1),每次替换>=3的块,替换后计数值置1,// 同时其它的块计数值加1 ,成了(1 3 2 ),见下面先进先出程序段}// 确定当前页面是否在物理块中,在继续,不在置换/////////////////////////////////////////////////////////////////////////////////// Block[0] = Data[0];for(i = 1;m < M;i++){int flag = 1;for(n = 0; n < m;n++){if(Data[i] == Block[n]) flag = 0;}if(flag == 0) continue;Block[m] = Data[i];m++;}//////////////////////////////////////////////////////////////////////////////////// 对有所数据操作for(i = 0;i < N;i++){// 增加countfor(j = 0;j < M;j++){count[j]++;find = false; // 表示块中有没有该数据for(j = 0;j < M;j++){if( Block[j] == Data[i] ){find = true;}}// 块中有该数据,判断下一个数据if( find ) continue;// 块中没有该数据ChangeTimes++; // 缺页次数++// 因为i是从0开始记,而M指的是个数,从1开始,所以i+1if( (i + 1) > M ){//获得要替换的块指针temp = 0;for(j = 0;j < M;j++){if( temp < count[j] ){temp = count[j];point = j; // 获得离的最远的指针}}}else point = i;// 替换Block[point] = Data[i];count[point] = 0; // 更新计数值// 保存要显示的数据for(j = 0;j < M;j++){DataShow[j][i] = Block[j];DataShowEnable[i < M ? (j <= i ? j : i) : j][i] = true; // 设置显示数据}}// 输出信息printf("\nFIFO => \n");DataOutput();}// 最近最久未使用置换算法void LRU(){int i,j;bool find;int point;int temp; // 临时变量int m = 1,n;ChangeTimes = 0;for(j = 0;j < M;j++){for(i = 0;i < N;i++){DataShowEnable[j][i] = false; // 初始化为false,表示没有要显示的数据}}for(i = 0;i < M;i++){count[i] = 0 ; // 初始化计数器}// 确定当前页面是否在物理块中,在继续,不在置换///////////////////////////////////////////////////////////////////////////////////Block[0] = Data[0];for(i = 1;m < M;i++){int flag = 1;for(n = 0; n < m;n++){if(Data[i] == Block[n]) flag = 0;}if(flag == 0) continue;Block[m] = Data[i];m++;}//////////////////////////////////////////////////////////////////////////////////// 对有所数据操作for(i = 0;i < N;i++){// 增加countfor(j = 0;j < M;j++){count[j]++;}find = false; // 表示块中有没有该数据for(j = 0;j < M;j++){if( Block[j] == Data[i] ){count[j] = 0;find = true;}}// 块中有该数据,判断下一个数据if( find ) continue;// 块中没有该数据ChangeTimes++;// 因为i是从0开始记,而BlockNum指的是个数,从1开始,所以i+1 if( (i + 1) > M ){//获得要替换的块指针temp = 0;for(j = 0;j < M;j++){if( temp < count[j] ){temp = count[j];point = j; // 获得离的最远的指针}}}else point = i;// 替换Block[point] = Data[i];count[point] = 0;// 保存要显示的数据for(j=0;j<M;j++){DataShow[j][i] = Block[j];DataShowEnable[i < M ?(j <= i ? j : i) : j][i] = true; // 设置显示数据}}// 输出信息printf("\nLRU => \n");DataOutput();}实验结果截图:程序运行:输入相应数据:选择相应算法:最佳置换算法:先进先出算法:最近最久未使用算法:。

Linux操作系统第三次实验报告

2.修改用户的UID。
3.修改用户的密码和有效期等信息。
4.创建系统用户*system(其中*为学生姓名拼音首字母组合)。
5.查看用户配置文件/etc/passwd和/etc/shadow,观察内容变化情况,可以在命令行中执行文件显示命令,也可以使用grep命令来查找。
二、创建和管理组账户
1.创建一个新的组*group(其中*为学生姓名拼音首字母组合)。
2.修改组账户名称和GID。
3.查看用户所属组。
4.将用户添加到新建组中。
5.将用户从该新建组中删除。
6.查看组配置文件/etc/group和/etc/gshadow获取组账户信息列表,观察变化情况并做简要说明。
指导教师评语:
实验报告
课程名称:Linux操作系统
任课教师:
授课学期:
学生班级:
学生姓名:
实验题目:创建和管理用户账户
实验成绩:
指导教师:
实验室:
日期:
节数:2
实验目的:掌握用户账户和组账户的命令行操作。
实验仪器、物品:已安装好Ubuntu桌面和管理用户账户
1.创建一个普通用户*user(其中*为学生姓名拼音首字母组合)。

【免费下载】东北大学操作系统第三次实验报告


命中次数++
被访问次数最少的
进程退出
};
int page_no;
char flag;
struct one_frame M_Frame[frame_num];
int main()
{
int i,j,k,t,m,kk,r1,r2,p1,p2;
int temp1,temp2,temp3;
int diseffect1=0,diseffect2=0;
实验 5:页面置换算法
一、 题目:编程实现 FIFO 和 LRU 算法
二、 目的: 进一步理解父子进程之间的关系; 理解内存页面调度的机理; 掌握页面置换算法的实现方法; 通过实验比较不同调度算法的优劣; 培养综合运用所学知识的能力。 页面置换算法是虚拟存储管理实现的关键,通过本次试验理解内存页面调度
int k1=0,k2=0,f1=0,f2=0;
float f;
int Access_series[total_instruction];
for(i=0; i<frame_num; i++) M_Frame[i].page_no=-1; printf("页面: ");
for(i=0; i<8; i++)
对全部高中资料试卷电气设备,在安装过程中以及安装结束后进行高中资料试卷调整试验;通电检查所有设备高中资料电试力卷保相护互装作置用调与试相技互术关,系电,力根通保据过护生管高产线中工敷资艺设料高技试中术卷资,配料不置试仅技卷可术要以是求解指,决机对吊组电顶在气层进设配行备置继进不电行规保空范护载高与中带资负料荷试下卷高问总中题体资,配料而置试且时卷可,调保需控障要试各在验类最;管大对路限设习度备题内进到来行位确调。保整在机使管组其路高在敷中正设资常过料工程试况中卷下,安与要全过加,度强并工看且作护尽下关可都于能可管地以路缩正高小常中故工资障作料高;试中对卷资于连料继接试电管卷保口破护处坏进理范行高围整中,核资或对料者定试对值卷某,弯些审扁异核度常与固高校定中对盒资图位料纸置试,.卷保编工护写况层复进防杂行腐设自跨备动接与处地装理线置,弯高尤曲中其半资要径料避标试免高卷错等调误,试高要方中求案资技,料术编试交写5、卷底重电保。要气护管设设装线备备置敷4高、调动设中电试作技资气高,术料课中并3中试、件资且包卷管中料拒含试路调试绝线验敷试卷动槽方设技作、案技术,管以术来架及避等系免多统不项启必方动要式方高,案中为;资解对料决整试高套卷中启突语动然文过停电程机气中。课高因件中此中资,管料电壁试力薄卷高、电中接气资口设料不备试严进卷等行保问调护题试装,工置合作调理并试利且技用进术管行,线过要敷关求设运电技行力术高保。中护线资装缆料置敷试做设卷到原技准则术确:指灵在导活分。。线对对盒于于处调差,试动当过保不程护同中装电高置压中高回资中路料资交试料叉卷试时技卷,术调应问试采题技用,术金作是属为指隔调发板试电进人机行员一隔,变开需压处要器理在组;事在同前发一掌生线握内槽图部内 纸故,资障强料时电、,回设需路备要须制进同造行时厂外切家部断出电习具源题高高电中中源资资,料料线试试缆卷卷敷试切设验除完报从毕告而,与采要相用进关高行技中检术资查资料和料试检,卷测并主处且要理了保。解护现装场置设。备高中资料试卷布置情况与有关高中资料试卷电气系统接线等情况,然后根据规范与规程规定,制定设备调试高中资料试卷方案。

兰州大学操作系统实验三实验报告

操作系统实验三
1.分别从至少三个虚拟终端登录,以树状形式列出你的系统中当前运行的所有进程及其PID。

找出你当前运行进程的所有祖先进程,并说明其各自的作用。

分析Linux系统中的进程的家族关系。

tty1
tty2
tty3
所有进程的祖先进程为systemd,是linux下的一种init软件。

Linux 软件中init是一个由内核启动的用户级进程,内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。

所以init始终是第一个进程(其进程编号始终为1)。

init有许多很重要的任务,比如像启动getty(用于用户登录)、实现运行级别、以及处理孤立进程等。

操作系统3 实验报告

1、编写三个程实现进程的创建及撤消。要求分别调用fork()、vfork()实现进程的创建,调用exit()终止进程,调用exec()为进程指定新的运行程序。
2、编写两个程实现进程的同步。要求分别调用fork()、sleep()、wait()、exit()实现两个进程的同步。
3、调试并分析结果。
四、实验过程与分析
甘肃政法学院
本科生实验报告
(三)
姓名:
学院:计算机科学学院
专业:信息管理与信息系统
班级:11级信息管理与信息系统班
实验课程名称:操作系统
实验日期: 2013年月日
指导教师及职称:
实验成绩:
开课时间:2013-2014学年一学期
甘肃政法学院实验管理中心印制
实验ቤተ መጻሕፍቲ ባይዱ目
进程创建
小组合作

姓名
班级
信管1班
学号
1.用fork()函数创建进程
用fork()函数创建进程时,语句调用系列如下:#include<sys/types.h>、#include<unistd.h>、Pit_t fork(void); fork()函数是一个单调用双返回的函数,也就是说,该函数有父进程调用,执行时,在父进程中返回子进程标识,在子进程中返回0。fork()调用后,子进程是父进程的一个复制,都是从fork()调用语句开始执行。
图1_1
运行结果如下:
图1_2
结果分析:产生这种结果的原因是由于程序运行时产生两个进程,有main()函数产生一个父进程以及程序执行中通过调用fork()产生的一个子进程,当执行到fork()后形成两个并发进程。
2.给进程指定一个新的运行程序的函数exec()
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

操作系统实验报告实验名称:实现ls命令实验计算机科学与技术学院目录一、实验目的和要求 (2)二、实验内容 (2)三、实验步骤 (2)四、实验结果与分析 (3)1.输出当前目录下文件 (3)2.输出指定目录下文件 (3)五、程序源代码 (5)六、实验体会 (7)一、实验目的和要求在linux系统下用C语言编写一个程序实现linux 系统下ls 命令的功能。

二、实验内容问题:编写一个程序实现linux 系统下ls 命令的功能。

首先通过Linux系统的文件目录流打开函数DIR *opendir(const char *name); 来先打开文件目录,然后通过系统调用函数struct dirent *readdir(DIR *dirp); 读取文件目录下的文件信息。

其中文件结构体dirent的结构如下:struct dirent{ino_t d_ino; /* inode number */off_t d_off; /* offset to the next dirent */unsigned short d_reclen; /* length of this record */unsigned char d_type; /* type of file; not supported by all file system types */char d_name[256]; /* filename */};三、实验步骤根据实验要求,实现指令ls的基本功能,即实现列出当前目录下的文件名,还有就是实现列出指定目录下的所有文件的文件名信息。

在编写好代码之后编译代码然后输入指令测试实验结果是否符合要求。

四、实验结果与分析1、输入指令:./myls输入默认的指令,输出当前目录下的文件名称,并用不同颜色区分文件夹和文件的区别。

实验结果如下图图1所示:图1 输出当前目录下所有的文件名2、输入指令:./myls ./Documents给定一个制定的路径,输出所给定路径下所有文件的文件名。

结果如下图图2所示:图2 输出指定目录下的所有文件名五、程序源代码/**************************FileName:myls.c*Author:*Date:2014/1/5***************************/#include <stdio.h>#include <stdlib.h>#include <dirent.h>#include <errno.h>#include <string.h>#include <sys/ioctl.h>#include <unistd.h>#include <termios.h>#include <sys/stat.h>#define SPACE 4/*自定义的字符串结构体*/typedef struct{char *str;/*实际内容*/unsigned length;/*字符串长度*/}String;/*文件信息结构体*/typedef struct{unsigned length;/*集合中文件名的数量*/unsigned i,j;/*i是行数,j是列数*/String *filenames;unsigned maxlen;/*文件名集合中最大的文件名长度*/char **formats;/*格式化输出序列*/}FormatInfo;/*获取无符号整型数十进制数的长度*/unsigned unsigned_length(unsigned n){unsigned length = 0;do{++length;n /= 10;}while(n)return length;}/*预读根目录,将格式化输出的信息保存在info中*/void Preread(char *root, FormatInfo *info){DIR *dir;unsigned i,j,count = 0;struct dirent *ptr;String filename;unsigned *g = NULL;/*g是根据目录下的目录项名的长度进行分组的辅助变量*/ unsigned width = 0;unsigned group = 0;unsigned max = 0;unsigned row = 1;unsigned pos = 0;struct winsize t_size;ioctl(STDIN_FILENO, TIOCGWINSZ, &t_size);/*获取终端的行数和列数*/ if(info == NULL){printf("Error! \"info\" can not be NULL!\n");return;}dir = opendir(root);if(dir == NULL){perror("Fail to open dir.\n");exit(1);}while(readdir(dir)) ++count;/*统计文件和目录的个数*/rewinddir(dir);/*回卷读取目录的指针*/info->filenames = (String *)malloc(sizeof(String) * count);g = (unsigned *)malloc(sizeof(unsigned) * count);i = 0;/*获取文件或目录名和计算其长度*/while((ptr = readdir(dir)) != NULL){filename.str = ptr->d_name;/*文件或目录名*/filename.length = strlen(ptr->d_name);info->filenames[i++] = filename;}/*对目录项根据目录名或文件名用选择排序法从小到大进行排序*/ for(i=0;i<count;++i){for(j=i;j<count;++j){if(strcmp(info->filenames[i].str,info->filenames[j].str) > 0){filename = info->filenames[i];info->filenames[i] = info->filenames[j];info->filenames[j] = filename;}}}/*用试探的方法测试最后列表的组数*/group = count;/*先假定分为count个列表*/row = 1;/*每列的行数为1*/do{for(j=0,width=0;j<group;++j){for(i=0,max=0;i<row;++i){/*找出每一列中文件或目录名最长的那一个*/pos = j*row + i;if(pos >= count) break;if(info->filenames[pos].length > max){max = info->filenames[pos].length;g[j] = max;/*把每个列表的最大宽度存放到g数组里*/}}width += (max + SPACE);/*将各组最长的文件或目录名的长度相加,把列表之间的间隔也算上*/}/*假如其总宽度大于终端的宽度(列数),则把分组列表的数量减少,继续试探。

*/if(width >= t_size.ws_col){--group;row = (count%group)?(count/group+1):(count/group);}else{break;/*否则,估算列表的数量结束*/}}while(1);info->formats = (char **)malloc(sizeof(char *) * group);info->maxlen = 0;for(i=0;i<group;++i){if(g[i] > info->maxlen)info->maxlen = g[i];/*这里找出最大文件或目录名的长度*/g[i] += SPACE;/*把列表之间的间隔算上*/j = unsigned_length(g[i]) + 4;info->formats[i] = (char *)malloc(sizeof(char) * j);sprintf(info->formats[i],"%%-%us",g[i]);/*这里就是组织格式化输出字符串的关键部分*/info->formats[i][j] = '\0';}putchar('\n');info->length = count;info->i = row;/*列表行数*/info->j = group;/*列表数量*/free(g);closedir(dir);}void Myls(char *root){FormatInfo fi;int i,j,pos,len;char *filepath = NULL;struct stat buf;Preread(root,&fi);/*预读目录*/len = strlen(root);filepath = (char *)malloc(sizeof(char) * (strlen(root)+fi.maxlen+1));filepath[0] = '\0';strcat(filepath,root);if(filepath[len-1] != '/'){filepath[len++] = '/';}for(i=0,pos=0;i<fi.i;++i){for(j=0;j<fi.j;++j){pos = j*fi.i + i;if(pos < fi.length){filepath[len] = '\0';strcat(filepath, fi.filenames[pos].str);stat(filepath, &buf);if(S_ISDIR(buf.st_mode)){printf("\033[01;36m");//Set color_dark-green}else{printf("\033[0m");//Set default_color}printf(fi.formats[j],fi.filenames[pos]);}else if(i<fi.i){break;}else{putchar('\n');return;}}putchar('\n');}printf("\033[0m");//Restore default_colorfree(filepath);}int main(int argc, char *argv[]){if(argc < 1){printf("参数错误!/n"); exit(1);}else if(argc == 1){Myls(".");}else{Myls(argv[1]);}return 0;}六、实验体会这次实验明显感觉到比前两次实验要简单一些,因为这些内容都是C语言学过的一些基本运用,知识要套用Linux系统中文件目录相关的一些系统调用和文件结构而已,然后进行一些简单的文件读取,以及文件信息的整理排序输出就可以实现ls指令的基本功能——列出文件目录中文件的文件名等信息。

相关文档
最新文档