实验4 文件操作.docx
《实验4 文件操作.docx》由会员分享,可在线阅读,更多相关《实验4 文件操作.docx(16页珍藏版)》请在冰点文库上搜索。
实验4文件操作
实验4、文件操作
学生姓名:
李亚军学号:
6100412196专业班级:
卓越计科121班
1.实验目的
通过编写文件读写及上锁的程序,进一步熟悉Linux中文件I/O相关的应用开发,并且熟练掌握open()、read()、write()、fcntl()等函数的使用。
2.实验内容
在Linux中FIFO是一种进程之间的管道通信机制。
Linux支持完整的FIFO通信机制。
本实验内容,通过使用文件操作,仿真FIFO(先进先出)结构以及生产者-消费者运行模型。
本实验中需要打开两个虚拟终端,分别运行生产者程序(producer)和消费者程序(customer)。
此时两个进程同时对同一个文件进行读写操作。
因为这个文件是临界资源,所以可以使用文件锁机制来保证两个进程对文件的访问都是原子操作。
先启动生产者进程,它负责创建仿真FIFO结构的文件(其实是一个普通文件)并投入生产,就是按照给定的时间间隔,向FIFO文件写入自动生成的字符(在程序中用宏定义选择使用数字还是使用英文字符),生产周期以及要生产的资源数通过参数传递给进程(默认生产周期为1s,要生产的资源数为10个字符)。
后启动的消费者进程按照给定的数目进行消费,首先从文件中读取相应数目的字符并在屏幕上显示,然后从文件中删除刚才消费过的数据。
为了仿真FIFO结构,此时需要使用两次复制来实现文件内容的偏移。
每次消费的资源数通过参数传递给进程,默认值为10个字符。
3.实验步骤
(1)实验流程图本实验的两个程序的流程图如图:
开始开始
(producer)(customer)
消费资源
创建FIFO结构文件(打印字符)
否
消费够了吗?
生产一个资源
是
上锁
上锁
将剩下的数据拷贝到
等待临时文件tmp中
一秒将“生产”的字符
写入到FIFO结构文件
用临时文件tmp覆盖
原数据文件,这样
模拟FIFO结构
解锁
解锁
生产完了吗?
删除临时文件
结束结束
图6.4节流程图
(2)代码
头部文件代码:
mylock.h
structmyflock
{
shortl_type;/*文件锁类型:
F_RDLOCK读取锁;F_WRLCK写入锁;F_UNLCK解锁*/
off_tl_start;/*相对位移量*/
shortl_whence;/*相对位移量的起点SEEK_SET;SEEK_CUR;SEEK_END:
*/
off_tl_len;/*加锁区域长度*/
pid_tl_pid;/**/
};
/*lock_set*/
intlock_set(intfd,inttype)
{
structmyflockold_lock,lock;
lock.l_whence=SEEK_SET;
lock.l_start=0;
lock.l_len=0;
lock.l_type=type;
lock.l_pid=-1;
/*判断文件是否可以上锁*/
fcntl(fd,F_GETLK,&lock);
if(lock.l_type!
=F_UNLCK)
{
/*判断文件不能上锁的原因*/
if(lock.l_type==F_RDLCK)/*该文件已有读取锁*/
{
printf("Readlockalreadysetby%d\n",lock.l_pid);
}
elseif(lock.l_type==F_WRLCK)/*该文件已有写入锁*/
{
printf("Writelockalreadysetby%d\n",lock.l_pid);
}
}
/*l_type可能已被F_GETLK修改过*/
lock.l_type=type;
/*根据不同的type值进行阻塞式上锁或解锁*/
if((fcntl(fd,F_SETLKW,&lock))<0)
{
printf("Lockfailed:
type=%d\n",lock.l_type);return1;
}
switch(lock.l_type)
{
caseF_RDLCK:
printf("Readlocksetby%d\n",getpid());
break;
caseF_WRLCK:
printf("Writelocksetby%d\n",getpid());
break;
caseF_UNLCK:
printf("Releaselockby%d\n",getpid());return1;
break;
default:
break;
}/*endofswitch*/
return0;
}
生产者程序的源代码:
producer.c
/*producer.c*/
#include
#include
#include
#include
#include
#include"mylock.h"
#defineMAXLEN10/*缓冲区大小最大值*/
#defineALPHABET1/*表示使用英文字符*/
#defineALPHABET_START'a'/*头一个字符,可以用'A'*/
#defineCOUNT_OF_ALPHABET26/*字母字符的个数*/
#defineDIGIT2/*表示使用数字字符*/
#defineDIGIT_START'0'/*头一个数字字符*/
#defineCOUNT_OF_DIGIT10/*数字字符的个数*/
#defineSIGN_TYPEALPHABET/*本实例用英文字符*/
constchar*fifo_file="./myfifo";/*!
"FIFO文件名*/
charbuff[MAXLEN];/*缓冲区*/
/*函数product()产生一个字符并写入仿真FIFO文件中*/
introduct(void)
{
intfd;
unsignedintsign_type,sign_start,sign_count,size;
staticunsignedintcounter=0;
/*打开!
"FIFO文件*/
if((fd=open(fifo_file,O_CREAT|O_RDWR|O_APPEND,0644))<0)
{
printf("Openfifofileerror\n");exit
(1);
}
sign_type=SIGN_TYPE;
switch(sign_type)
{
caseALPHABET:
/*英文字符*/
{
sign_start=ALPHABET_START;
sign_count=COUNT_OF_ALPHABET;
}
break;
caseDIGIT:
/*数字字符*/
{
sign_start=DIGIT_START;
sign_count=COUNT_OF_DIGIT;
}
break;
default:
{
return-1;
}
}/*endofswitch*/
sprintf(buff,"%c",(sign_start+counter));counter=(counter+1)%sign_count;
lock_set(fd,F_WRLCK);/*上写锁*/
if((size=write(fd,buff,strlen(buff)))<0)
{
printf("Producer:
writeerror\n");return-1;
}
lock_set(fd,F_UNLCK);/*解锁*/
close(fd);
return0;
}
intmain(intargc,char*argv[])
{
inttime_step=1;/*生产周期*/
inttime_life=10;/*需要生产的资源数*/
if(argc>1)
{/*第一个参数表示生产周期*/
sscanf(argv[1],"%d",&time_step);
}
if(argc>2)
{/*第二个参数表示需要生产的资源数*/
sscanf(argv[2],"%d",&time_life);
}
while(time_life--)
{
if(product()<0)
{
break;
}
sleep(time_step);
}
exit(EXIT_SUCCESS);
}
消费者程序的源代码:
customer.c
/*customer.c*/
#include
#include
#include
#include
#include
#include"mylock.h"
#defineMAX_FILE_SIZE100*1024*1024/*100M*/
constchar*fifo_file="./myfifo";/*仿真FIFO文件名*/
constchar*tmp_file="./tmp";/*临时文件名*/
/*资源消费函数customing*/
intcustoming(constchar*myfifo,intneed)
{
intfd;
charbuff;
intcounter=0;
if((fd=open(myfifo,O_RDONLY))<0)
{
printf("Functioncustomingerror\n");
return-1;
}
printf("Enjoy:
");
lseek(fd,SEEK_SET,0);
while(counter{
while((read(fd,&buff,1)==1)&&(counter{
fputc(buff,stdout);/*-.就是在屏幕上/0的显示*/
counter++;
}
}
fputs("\n",stdout);
close(fd);
return0;
}
/*myfilecopy()函数:
实现从sour_file文件的offset偏移处开始将count个字节数据复制到dest_file文件*/
intmyfilecopy(constchar*sour_file,constchar*dest_file,intoffset,intcount,intcopy_mode)
{
intin_file,out_file;
intcounter=0;
charbuff_unit;
if((in_file=open(sour_file,O_RDONLY|O_NONBLOCK))<0)
{
printf("Functionmyfilecopyerrorinsourcefile\n");return-1;
}
if((out_file=open(dest_file,O_CREAT|O_RDWR|O_TRUNC|O_NONBLOCK,0644))<0)
{
printf("Functionmyfilecopyerrorindestinationfile:
");return-1;
}
lseek(in_file,offset,SEEK_SET);
while((read(in_file,&buff_unit,1)==1)&&(counter{
write(out_file,&buff_unit,1);counter++;
}
close(in_file);
close(out_file);
return0;
}
/*custom()函数:
实现FIFO消费者*/
intcustom(intneed)
{
intfd;
/*对资源进行消费,need表示该消费的资源数目*/
customing(fifo_file,need);
if((fd=open(fifo_file,O_RDWR))<0)
{
printf("Functionmyfilecopyerrorinsource_file:
");
return-1;
}
/*为了模拟FIFO结构,对整个文件进平行行移动*/
lock_set(fd,F_WRLCK);
myfilecopy(fifo_file,tmp_file,need,MAX_FILE_SIZE,0);
myfilecopy(tmp_file,fifo_file,0,MAX_FILE_SIZE,0);
lock_set(fd,F_UNLCK);
unlink(tmp_file);
close(fd);
return0;
}
intmain(intargc,char*argv[])
{
intcustomer_capacity=10;
if(argc>1)/*第一个参数指定需要消费的资源数目,默认值为10*/
{
sscanf(argv[1],"%d",&customer_capacity);
}
if(customer_capacity>0)
{
custom(customer_capacity);
}
exit(EXIT_SUCCESS);
}
(3)分别编译生产者程序producer.c和消费者程序customer.c
(4)确保编译没有错误后,先在控制台终端1上运行生产者程序:
./producer120
再在控制台终端2上运行消费者程序:
./customer5
4.完成实验报告
(1)将实验过程和实验结果截图
(2)认真阅读程序代码,参考代码并根据实验结果,完成实验总结。
该程序利用文件模拟管道来传输数据,使用设置文件描述符的状态来实现文件上锁与解锁的功能,防止在读写同一文件由于同步操作产生错误,对比于操作系统的信号同步,其原理是一样的。
5.附加实验作业:
用write,read,open等系统调用编写分别实现如下功能的程序`(要求进行必要的出错检查):
(1)创建一个文件testfile.txt,文件内容从键盘输入;
(2)将testfile.txt的内容显示在屏幕上,并将testfile.txt的内容复制到一个新的文件file2.txt中。
input.c
#include
#include
#include
#include
#include
constchar*fifo_file="./testfile.txt";
intmain()
{
intfd;
charbuffer[1024];
if((fd=open(fifo_file,O_CREAT|O_RDWR|O_APPEND,0644))<0)
{
printf("Openfifofileerror\n");exit
(1);
}
printf("pleaseinputsomedata:
");
scanf("%s",buffer);
write(fd,buffer,strlen(buffer));
close(fd);
return0;
}
copy_output.c
#include
#include
#include
#include
constchar*fifo_file_src="./testfile.txt";
constchar*fifo_file_dst="./file2.txt";
intmain()
{
intfd_src;
intfd_dst;
intreal_num;
charbuffer[1024];
if((fd_src=open(fifo_file_src,O_RDWR|O_APPEND))<0)//第三个参数便是创建的文件的属性
{
printf("Opentextfileerror\n");exit
(1);
}
if((fd_dst=open(fifo_file_dst,O_CREAT|O_RDWR|O_APPEND,0644))<0)
{
printf("Openfile2error\n");exit
(1);
}
buffer[100]='0';
while((real_num=read(fd_src,buffer,100))!
=0)
{
if(real_num==-1)
{
printf("readtextfileerror\n");exit
(1);
}
if(write(fd_dst,buffer,real_num)!
=real_num)
{
printf("writetextfileerror\n");exit
(1);
}
printf("%s",buffer);//打印输出
//memzero(buffer);//
}
printf("\n");//
close(fd_src);
close(fd_dst);
return0;
}