版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
嵌入式編程技術(shù)
課程總體情況成績(jī):期末考試80%,平時(shí)10(考勤+作業(yè)),實(shí)驗(yàn)10%學(xué)時(shí)安排:教師授課32學(xué)時(shí),實(shí)驗(yàn)32學(xué)時(shí)教材:《從實(shí)踐中學(xué)嵌入式Linux應(yīng)用程序開發(fā)》重點(diǎn)內(nèi)容:嵌入式文件I/O編程、多任務(wù)編程、進(jìn)程間通信、多線程編程、網(wǎng)絡(luò)編程、設(shè)備驅(qū)動(dòng)編程。補(bǔ)充內(nèi)容:QT編程(GUI)、BOA移植及編程學(xué)習(xí)方法:理解+實(shí)踐3
第2章嵌入式文件I/O編程在Linux系統(tǒng)中,大部分設(shè)備都會(huì)抽象成一個(gè)文件,這樣對(duì)它們的操作就像對(duì)文件的操作一樣。在嵌入式應(yīng)用開發(fā)中,文件I/O編程是最常用也是最基本的內(nèi)容。
4
第2章嵌入式文件I/O編程系統(tǒng)調(diào)用及用戶編程接口系統(tǒng)調(diào)用、用戶編程接口、系統(tǒng)命令的概念Linux文件I/O系統(tǒng)概述虛擬文件系統(tǒng)VFS、Linux中文件及文件描述符底層文件I/O操作基本文件操作、文件鎖、多路復(fù)用嵌入式Linux串口應(yīng)用編程標(biāo)準(zhǔn)I/O編程文件讀寫及上鎖綜合實(shí)例5
2.1.1系統(tǒng)調(diào)用
2.1Linux系統(tǒng)調(diào)用及用戶編程接口系統(tǒng)調(diào)用是指操作系統(tǒng)提供給用戶程序調(diào)用的一組“特殊”接口,用戶程序可以通過這組“特殊”接口獲得操作系統(tǒng)內(nèi)核提供的服務(wù)。例如用戶可以通過進(jìn)程控制相關(guān)的系統(tǒng)調(diào)用來創(chuàng)建進(jìn)程、實(shí)現(xiàn)進(jìn)程之間的通信等。在Linux中,為了更好地保護(hù)內(nèi)核空間,將程序的運(yùn)行空間分為內(nèi)核空間和用戶空間(也稱為內(nèi)核態(tài)和用戶態(tài)),用戶進(jìn)程在通常情況下不允許訪問內(nèi)核數(shù)據(jù),也無法使用內(nèi)核函數(shù),只能在用戶空間操作用戶數(shù)據(jù),調(diào)用用戶空間的函數(shù)。6
2.1.1系統(tǒng)調(diào)用
2.1Linux系統(tǒng)調(diào)用及用戶編程接口Linux系統(tǒng)調(diào)用非常精簡(jiǎn),它繼承了Unix系統(tǒng)調(diào)用中最基本的部分。這些系統(tǒng)調(diào)用按照功能邏輯大致可以分為進(jìn)程控制、進(jìn)程間通信、文件系統(tǒng)控制、存儲(chǔ)管理、網(wǎng)絡(luò)管理、套接字控制、用戶管理等幾類。7
2.1.2用戶編程接口
2.1Linux系統(tǒng)調(diào)用及用戶編程接口系統(tǒng)調(diào)用并不直接與程序員進(jìn)行交互,實(shí)際使用中程序員調(diào)用的通常是用戶編程接口(API)。例如:創(chuàng)建進(jìn)程的API函數(shù)fork()對(duì)應(yīng)于內(nèi)核空間的sys_fork()系統(tǒng)調(diào)用。一些API函數(shù)需要幾個(gè)系統(tǒng)調(diào)用來共同完成函數(shù)的功能,也有一些API函數(shù)不需要調(diào)用系統(tǒng)調(diào)用。8
2.1.2用戶編程接口
2.1Linux系統(tǒng)調(diào)用及用戶編程接口在Linux中,用戶編程接口(API)遵循了在Unix中最流行的應(yīng)用編程界面標(biāo)準(zhǔn)——POSIX(PortableOperatingSystemInterface)標(biāo)準(zhǔn)。POSIX標(biāo)準(zhǔn)是由IEEE和ISO/IEC共同開發(fā)的標(biāo)準(zhǔn)系統(tǒng)。該標(biāo)準(zhǔn)基于當(dāng)時(shí)現(xiàn)有的Unix實(shí)踐和經(jīng)驗(yàn),描述了操作系統(tǒng)的系統(tǒng)調(diào)用編程接口(實(shí)際上就是API),用于保證應(yīng)用程序可以在源代碼一級(jí)上在多種操作系統(tǒng)上移植運(yùn)行。這些系統(tǒng)調(diào)用編程接口主要是通過C庫(libc)實(shí)現(xiàn)的。9
2.1.3系統(tǒng)命令
2.1Linux系統(tǒng)調(diào)用及用戶編程接口系統(tǒng)命令相對(duì)API更高了一層,它實(shí)際上一個(gè)可執(zhí)行程序,它的內(nèi)部引用了用戶編程接口(API)來實(shí)現(xiàn)相應(yīng)的功能,它們之間的關(guān)系如圖:10
2.2.1虛擬文件系統(tǒng)
Linux系統(tǒng)成功的關(guān)鍵因素之一就是具有與其他操作系統(tǒng)和諧共存的能力。Linux的文件系統(tǒng)由兩層結(jié)構(gòu)構(gòu)建。第一層是虛擬文件系統(tǒng)(VFS),第二層是各種不同的具體的文件系統(tǒng)。
2.2Linux文件I/O系統(tǒng)概述11
2.2.1虛擬文件系統(tǒng)
2.2Linux文件I/O系統(tǒng)概述
12
2.2.2Linux中文件及文件描述符
Linux目前支持7種文件類型:普通文件、目錄文件、鏈接文件、塊設(shè)備文件、字符設(shè)備文件、管道文件、套接字文件。
對(duì)于Linux而言,所有對(duì)設(shè)備和文件的操作都是使用文件描述符來進(jìn)行的。文件描述符是一個(gè)非負(fù)的整數(shù),它是一個(gè)索引值,并指向在內(nèi)核中每個(gè)進(jìn)程打開文件的記錄表。當(dāng)打開一個(gè)現(xiàn)存文件或創(chuàng)建一個(gè)新文件時(shí),內(nèi)核就向進(jìn)程返回一個(gè)文件描述符;當(dāng)需要讀寫文件時(shí),也需要把文件描述符作為參數(shù)傳遞給相應(yīng)的函數(shù)。
2.2Linux文件I/O系統(tǒng)概述13
2.2.2Linux中文件及文件描述符
基于文件描述符的I/O操作是Linux中最常用的操作之一。例如一個(gè)進(jìn)程啟動(dòng)時(shí),都會(huì)打開3個(gè)文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)出錯(cuò)處理。2.2Linux文件I/O系統(tǒng)概述文件描述符宏標(biāo)準(zhǔn)輸入0STDIN_FILENO標(biāo)準(zhǔn)輸出1STDOUT_FILENO標(biāo)準(zhǔn)出錯(cuò)2STDERR_FILENO14
文件I/O操作的系統(tǒng)調(diào)用主要有5個(gè)函數(shù):open()、read()、write()、lseek()和close()。這些函數(shù)的特點(diǎn)是不帶緩存,直接對(duì)文件(包括設(shè)備)進(jìn)行讀寫操作。這些函數(shù)是Posix的組成部分,但不是ANSIC的組成部分。2.3底層文件I/O操作15
2.3.1基本文件操作open函數(shù)是用于打開或創(chuàng)建文件,在打開或創(chuàng)建文件時(shí)可以指定文件的屬性及用戶的權(quán)限等各種參數(shù)。所需頭文件:
#include<sys/types.h> #include<sys/stat.h>
#include<fcntl.h>原型:
intopen(constchar*pathname,intflags,intperms)
2.3底層文件I/O操作16
2.3.1基本文件操作open函數(shù)語法要點(diǎn)
2.3底層文件I/O操作17
2.3.1基本文件操作open函數(shù)語法要點(diǎn)
2.3底層文件I/O操作18
2.3.1基本文件操作close()函數(shù)是用于關(guān)閉一個(gè)被打開的文件。close函數(shù)語法要點(diǎn):
2.3底層文件I/O操作19
2.3.1基本文件操作read()函數(shù)是用于將從指定的文件描述符中讀出的數(shù)據(jù)放到緩存區(qū)中,并返回實(shí)際讀入的字節(jié)數(shù)。read函數(shù)語法要點(diǎn):
2.3底層文件I/O操作20
2.3.1基本文件操作write()函數(shù)是用于向打開的文件寫數(shù)據(jù),寫操作從文件的當(dāng)前指針位置開始。write函數(shù)語法要點(diǎn):
2.3底層文件I/O操作21
2.3.1基本文件操作lseek()函數(shù)是用于在指定的文件描述符中將文件指針定位到相應(yīng)的位置。lseek函數(shù)語法要點(diǎn):
2.3底層文件I/O操作22
2.3.1基本文件操作lseek()函數(shù)是用于在指定的文件描述符中將文件指針定位到相應(yīng)的位置。lseek函數(shù)語法要點(diǎn):
2.3底層文件I/O操作23
2.3.1基本文件操作函數(shù)使用示例:
基本功能:從一個(gè)文件(源文件)中讀取最后10KB的數(shù)據(jù)并復(fù)制到另一個(gè)文件(目標(biāo)文件)。源文件以只讀方式打開,目標(biāo)文件以只寫方式打開。若目標(biāo)文件不存在,可以創(chuàng)建并設(shè)置權(quán)限的初始值為644,即文件的所有者可讀可寫,文件所屬組和其他用戶只能讀。
2.3底層文件I/O操作24
2.3.1基本文件操作#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdlib.h>#include<stdio.h>#define BUFFER_SIZE 1024 /*每次讀寫緩存大小#define SRC_FILE_NAME "src_file" /*源文件名*/#define DEST_FILE_NAME "dest_file"/*目標(biāo)文件名*/#define OFFSET 10240 /*復(fù)制的數(shù)據(jù)大小*/2.3底層文件I/O操作25
2.3.1基本文件操作intmain(){ intsrc_file,dest_file; unsignedcharbuff[BUFFER_SIZE]; intreal_read_len; /*以只讀方式打開源文件*/ src_file=open(SRC_FILE_NAME,O_RDONLY); /*以只寫方式打開目標(biāo)文件,若此文件不存在則創(chuàng)建該文件,訪問權(quán)限值為644*/ dest_file=open(DEST_FILE_NAME,O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if(src_file<0||dest_file<0) { printf("Openfileerror\n"); exit(1); }2.3底層文件I/O操作26
2.3.1基本文件操作 lseek(src_file,-OFFSET,SEEK_END); /*讀取源文件的最后10KB數(shù)據(jù)并寫到目標(biāo)文件中,每次讀寫1KB*/ while((real_read_len=read(src_file,buff,sizeof(buff)))>0) { write(dest_file,buff,real_read_len); } close(dest_file); close(src_file); return0;}2.3底層文件I/O操作27
2.3.2文件鎖在文件已經(jīng)共享的情況下,為避免競(jìng)爭(zhēng)共享資源產(chǎn)生錯(cuò)誤,Linux通常的方法是給文件上鎖。建議性鎖:每個(gè)要求上鎖文件的進(jìn)程都要檢查是否有鎖存在,并尊重已有的鎖。強(qiáng)制性鎖:由內(nèi)核執(zhí)行。當(dāng)一個(gè)文件被上鎖進(jìn)行寫入操作的時(shí)候,內(nèi)核將阻止其他進(jìn)程對(duì)其進(jìn)行讀寫操作。記錄鎖:對(duì)文件的某一記錄上鎖,又分為讀取鎖(共享鎖)和寫入鎖(排斥鎖)。實(shí)現(xiàn)文件上鎖的函數(shù):lockf()和fcntl()。2.3底層文件I/O操作28
2.3.2文件鎖fcntl()函數(shù)具有很豐富的功能,它可以對(duì)已打開的文件描述符進(jìn)行各種操作,不僅包括管理文件鎖,還包括獲得設(shè)置文件描述符和文件描述符標(biāo)志、文件描述符的復(fù)制等很多功能。
2.3底層文件I/O操作29
2.3.2文件鎖fcntl()函數(shù)語法要點(diǎn)
2.3底層文件I/O操作30
2.3.2文件鎖fcntl()函數(shù)語法要點(diǎn)
2.3底層文件I/O操作31
2.3.2文件鎖fcntl()函數(shù)第三個(gè)參數(shù)lock說明lock為flock類型的結(jié)構(gòu)體,flock的定義為:structflock { shortl_type; off_tl_start; shortl_whence;
off_tl_len; pid_tl_pid;}
2.3底層文件I/O操作32
2.3.2文件鎖fcntl()函數(shù)第三個(gè)參數(shù)lock說明
2.3底層文件I/O操作對(duì)整個(gè)文件加鎖:l_start設(shè)為0,l_whence設(shè)為SEEK_SET,l_len設(shè)為0。33
2.3.2文件鎖fcntl()使用實(shí)例源文件1:lock_set.cintlock_set(intfd,inttype){ structflocklock; lock.l_whence=SEEK_SET; lock.l_start=0; lock.l_len=0; lock.l_type=type; lock.l_pid=-1;
2.3底層文件I/O操作34
2.3.2文件鎖fcntl()使用實(shí)例 /*判斷文件是否可以上鎖*/ 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); } }
2.3底層文件I/O操作35
2.3.2文件鎖fcntl()使用實(shí)例 /*l_type可能已被F_GETLK修改過*/ lock.l_type=type; /*根據(jù)不同的type值進(jìn)行阻塞式上鎖或解鎖*/ 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;
2.3底層文件I/O操作36
2.3.2文件鎖fcntl()使用實(shí)例 caseF_WRLCK: { printf("Writelocksetby%d\n",getpid()); } break; caseF_UNLCK: { printf("Releaselockby%d\n",getpid()); return1;
} break; default: break; }/*endofswitch*/ return0;
}
2.3底層文件I/O操作37
2.3.2文件鎖fcntl()使用實(shí)例主程序源文件:write_lock.c#include<unistd.h>#include<sys/file.h>#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<stdlib.h>#include"lock_set.c"intmain(void)
{ intfd; fd=open("hello",O_RDWR|O_CREAT,0644);
2.3底層文件I/O操作38
2.3.2文件鎖fcntl()使用實(shí)例 if(fd<0)
{ printf("Openfileerror\n"); exit(1); } /*給文件上寫入鎖*/ lock_set(fd,F_WRLCK); getchar(); /*給文件解鎖*/ lock_set(fd,F_UNLCK); getchar(); close(fd); return0;}
2.3底層文件I/O操作39
2.3.2文件鎖fcntl()使用實(shí)例2——讀取鎖主程序源文件:fcntl_read.c#include<unistd.h>#include<sys/file.h>#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<stdlib.h>#include"lock_set.c"intmain(void)
{ intfd; fd=open("hello",O_RDWR|O_CREAT,0644);
2.3底層文件I/O操作40
2.3.2文件鎖fcntl()使用實(shí)例 if(fd<0)
{ printf("Openfileerror\n"); exit(1); } /*給文件上寫入鎖*/ lock_set(fd,F_RDLCK); getchar(); /*給文件解鎖*/ lock_set(fd,F_UNLCK); getchar(); close(fd); return0;}
2.3底層文件I/O操作41
2.3.3多路復(fù)用I/O處理模型阻塞I/O模型若所調(diào)用的I/O函數(shù)沒有完成相關(guān)的功能,則會(huì)使進(jìn)程掛起,直到相關(guān)數(shù)據(jù)到達(dá)才會(huì)返回。如:
fcntl(fd,F_SETLKW,&lock);非阻塞模型 當(dāng)請(qǐng)求的I/O操作不能完成時(shí),則不讓進(jìn)程睡眠,而且立即返回。如open()、read()、write()等操作
2.3底層文件I/O操作42
2.3.3多路復(fù)用I/O處理模型I/O多路轉(zhuǎn)接模型
如果請(qǐng)求的I/O操作阻塞,且它不是真正的阻塞I/O,而是讓其中的一個(gè)函數(shù)等待,在這期間,I/O還能進(jìn)行其他操作。信號(hào)驅(qū)動(dòng)I/O模型 在該模型下,進(jìn)程要定義信號(hào)處理程序,系統(tǒng)可以自動(dòng)捕獲特定信號(hào)的到來,從而啟動(dòng)I/O。 該模型的好處是當(dāng)?shù)却龜?shù)據(jù)到達(dá)時(shí),主程序繼續(xù)執(zhí)行,只有收到SIGIO信號(hào)時(shí)才去處理數(shù)據(jù)。2.3底層文件I/O操作43
2.3.3多路復(fù)用I/O處理模型異步I/O模型 在這種模型下,進(jìn)程先讓內(nèi)核啟動(dòng)I/O操作,并在整個(gè)操作完成后通知該進(jìn)程。 與信號(hào)驅(qū)動(dòng)I/O的區(qū)別:信號(hào)驅(qū)動(dòng)I/O由內(nèi)核通知進(jìn)程何時(shí)可以啟動(dòng)I/O,而異步I/O模型是由內(nèi)核通知進(jìn)程I/O操作何時(shí)完成。
2.3底層文件I/O操作44
2.3.3多路復(fù)用
select()和poll()函數(shù)屬于I/O多路轉(zhuǎn)接模型,是處理I/O復(fù)用的一個(gè)高效的方法。
它可以具體設(shè)置程序中每一個(gè)所關(guān)心的文件描述符的條件、希望等待的時(shí)間等,從select()和poll()函數(shù)返回時(shí),內(nèi)核會(huì)通知用戶準(zhǔn)備好的文件描述符的數(shù)量、已準(zhǔn)備好的條件(或事件)等。通過使用select()和poll()函數(shù)的返回結(jié)果,就可以調(diào)用相應(yīng)的I/O處理函數(shù)了。2.3底層文件I/O操作45
2.3.3多路復(fù)用select()函數(shù)的語法格式:
2.3底層文件I/O操作46
2.3.3多路復(fù)用select()函數(shù)的語法格式:
2.3底層文件I/O操作47
2.3.3多路復(fù)用select()函數(shù)根據(jù)希望進(jìn)行的文件操作對(duì)文件描述符進(jìn)行了分類處理,對(duì)文件描述符的處理涉及4個(gè)宏函數(shù):FD_ZERO(fd_set*set): 清除一個(gè)文件描述符集FD_SET(intfd,fd_set*set): 將一個(gè)文件描述符加入文 件描符集中FD_CLR(intfd,fd_set*set): 將一個(gè)文件描述符從文件 描述符集中清除FD_ISSET(intfd,fd_set*set):如果fd是set的一個(gè)元素, 則返回非零值。2.3底層文件I/O操作48
2.3.3多路復(fù)用structtimeout結(jié)構(gòu)體的定義(bits/time.h):2.3底層文件I/O操作
structtimeval{__time_ttv_sec;/*Seconds.*/__suseconds_ttv_usec;/*Microseconds.*/};49
2.3.3多路復(fù)用——poll()函數(shù)poll函數(shù)語法格式:
2.3底層文件I/O操作50
2.3.3多路復(fù)用——poll()函數(shù)poll函數(shù)語法格式:intpoll(structpollfd*fds,intnumfds,inttimeout)
2.3底層文件I/O操作51
2.3.3多路復(fù)用——poll()函數(shù)poll函數(shù)語法格式:intpoll(structpollfd*fds,intnumfds,inttimeout)timeout:poll阻塞的超時(shí)時(shí)間(ms),小于等于0表示無限等待。
2.3底層文件I/O操作52
2.3.3多路復(fù)用——實(shí)例 通過調(diào)用poll()函數(shù)來監(jiān)聽三個(gè)終端的輸入(分別重定向到兩個(gè)管道文件的虛擬終端以及主程序所運(yùn)行的虛擬終端)并分別進(jìn)行相應(yīng)的處理。
建立一個(gè)poll()函數(shù)監(jiān)視的讀文件描述符集,其中包含三個(gè)文件描述符,分別為標(biāo)準(zhǔn)輸入文件描述符和兩個(gè)管道文件描述符。通過監(jiān)視主程序的虛擬終端標(biāo)準(zhǔn)輸入來實(shí)現(xiàn)程序的控制(如程序結(jié)束);以兩個(gè)管道作為數(shù)據(jù)輸入,主程序?qū)膬蓚€(gè)管道讀取的輸入字符串寫入到輸出文件(屏幕)。
2.3底層文件I/O操作53
2.3.3多路復(fù)用——實(shí)例#include<fcntl.h>#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>#include<time.h>#include<errno.h>#include<poll.h>#defineMAX_BUFFER_SIZE 1024 /*緩沖區(qū)大小*/#defineIN_FILES 3 /*多路復(fù)用輸入文件數(shù)目*/#defineTIME_DELAY 60000 /*超時(shí)時(shí)間秒數(shù):60秒*/#defineMAX(a,b) ((a>b)?(a):(b))
2.3底層文件I/O操作小技巧:查看使用某個(gè)函數(shù)時(shí)需要哪些頭文件:man函數(shù)名
錯(cuò)誤信息處理:
全局變量errnovoidperror(constchar*s);char*strerror(interrno);54
2.3.3多路復(fù)用——實(shí)例intmain(void){ structpollfdfds[IN_FILES]; charbuf[MAX_BUFFER_SIZE]; inti,res,real_read,maxfd;
/*首先按一定的權(quán)限打開兩個(gè)源文件*/ fds[0].fd=0; if((fds[1].fd=open("in1",O_RDONLY|O_NONBLOCK))<0) { printf("Openin1error\n"); return1; }
2.3底層文件I/O操作55
2.3.3多路復(fù)用——實(shí)例
if((fds[2].fd=open("in2",O_RDONLY|O_NONBLOCK))<0) { printf("Openin2error\n"); return1; }
/*取出兩個(gè)文件描述符中的較大者*/ for(i=0;i<IN_FILES;i++) { fds[i].events=POLLIN; }
2.3底層文件I/O操作56
2.3.3多路復(fù)用——實(shí)例 while(fds[0].events||fds[1].events||fds[2].events) { if(poll(fds,IN_FILES,0)<0) { printf("PollerrororTimeout\n"); return1; }2.3底層文件I/O操作57
2.3.3多路復(fù)用——實(shí)例for(i=0;i<IN_FILES;i++){ if(fds[i].revents)/*判斷在哪個(gè)文件上發(fā)生了事件*/ { memset(buf,0,MAX_BUFFER_SIZE); real_read=read(fds[i].fd,buf,MAX_BUFFER_SIZE); if(real_read<0) { if(errno!=EAGAIN) { return1;/*系統(tǒng)錯(cuò)誤,結(jié)束運(yùn)行*/ } } elseif(!real_read) { close(fds[i].fd); fds[i].events=0;/*取消對(duì)該文件的監(jiān)聽*/ }
2.3底層文件I/O操作對(duì)不同的輸入做相應(yīng)處理……58
2.3.3多路復(fù)用——實(shí)例else{ if(i==0)/*如果在標(biāo)準(zhǔn)輸入上有數(shù)據(jù)輸入時(shí)*/ { if((buf[0]=='q')||(buf[0]=='Q')){ return1;/*輸入"q"或"Q"則會(huì)退出*/ } } else {/*將讀取的數(shù)據(jù)輸出到終端上*/ buf[real_read]='\0'; printf("%s",buf); } }/*endofifreal_read*/ }/*endofifrevents*/ }/*endoffor*/ }/*endofwhile*/ exit(0);}
2.3底層文件I/O操作59
2.3.3多路復(fù)用——實(shí)例如何驗(yàn)證該多路復(fù)用程序?編譯程序;創(chuàng)建兩個(gè)管道;
mknodin1p mknodin2p啟動(dòng)實(shí)例程序;啟動(dòng)兩個(gè)新的虛擬終端,通過輸出重定向的方法向管道輸出數(shù)據(jù)。
cat>in1cat>in2在控制終端輸入q或Q,退出程序。2.3底層文件I/O操作60
2.4.1串口編程基礎(chǔ)知識(shí)常見的數(shù)據(jù)通信的基本方式可分為并行通信與串行通信兩種。并行通信是指利用多條數(shù)據(jù)傳輸線將一個(gè)字?jǐn)?shù)據(jù)的各比特位同時(shí)傳送。它的特點(diǎn)是傳輸速度快,適用于傳輸距離短且傳輸速度較高的通信。串行通信是指利用一條傳輸線將數(shù)據(jù)以比特位為單位順序傳送。特點(diǎn)是通信線路簡(jiǎn)單,利用簡(jiǎn)單的線纜就可實(shí)現(xiàn)通信,降低成本,適用于傳輸距離長(zhǎng)且傳輸速度較慢的通信。2.4嵌入式Linux串口應(yīng)用編程61
2.4.1串口編程基礎(chǔ)知識(shí)串口是計(jì)算機(jī)一種常用的接口,常用的串口有RS-232-C接口。
DB9串口接口:2.4嵌入式Linux串口應(yīng)用編程62
2.4.1串口編程基礎(chǔ)知識(shí)在Linux中,設(shè)備文件一般都位于/dev下,其中串口1和串中2對(duì)應(yīng)的設(shè)備名稱為“/dev/ttyS0”和“/dev/ttyS1”,對(duì)串口的讀寫可以使用簡(jiǎn)單的read()和write()函數(shù)來完成,所不同的是需要對(duì)串口的其他參數(shù)進(jìn)行配置。S3C2410X內(nèi)部有2個(gè)獨(dú)立的UART控制器,每個(gè)控制器都可以工作在Interrupt或DMA模式。UART的操作主要可分為以下幾個(gè)部分:數(shù)據(jù)發(fā)送、數(shù)據(jù)接收、產(chǎn)生中斷、設(shè)置波特率、Loopback模式、紅外模式以及硬軟流控模式。2.4嵌入式Linux串口應(yīng)用編程63
2.4.2串口配置串口設(shè)置主要是設(shè)置structtermios結(jié)構(gòu)體的各個(gè)成員#include<termios.h>structtermios{ unsignedshortc_iflag; /*輸入模式標(biāo)志*/ unsignedshortc_oflag; /*輸出模式標(biāo)志*/ unsignedshortc_cflag; /*控制模式標(biāo)志*/ unsignedshortc_lflag; /*本地模式標(biāo)志*/ unsignedcharc_line; /*線路規(guī)程*/ unsignedcharc_cc[NCC]; /*控制特性*/ speed_t c_ispeed; /*輸入速度*/ speed_t c_ospeed; /*輸出速度*/};
2.4嵌入式Linux串口應(yīng)用編程64
2.4.2串口配置終端的三種工作模式:規(guī)范模式:所有的輸入基于行進(jìn)行處理。用戶輸入行結(jié)束符之前,系統(tǒng)調(diào)用read()函數(shù)讀不到用戶輸入的任何字符。非規(guī)范模式:所有的輸入是即時(shí)有效的,不需要輸入行結(jié)束符,也不能進(jìn)行行編輯,參數(shù)MIN(c_cc[VMIN])和TIME(c_cc[VTIME])決定read()函數(shù)的調(diào)用方式。原始模式:一種特殊的非規(guī)范模式,此模式下所有輸入數(shù)據(jù)以字節(jié)為單位進(jìn)行處理,而且終端不可回顯。通過在termios結(jié)構(gòu)的c_lflag中設(shè)置ICANNO標(biāo)志來定義終端是以規(guī)范模式還是以非規(guī)范模式工作;通過調(diào)用cfmakeraw()函數(shù)可以將終端設(shè)置為原始模式。
表2.11-2.152.4嵌入式Linux串口應(yīng)用編程65
2.4.2串口配置2.4嵌入式Linux串口應(yīng)用編程66
2.4.2串口配置保存原先串口設(shè)置使用函數(shù)tcgetattr(fd,&old_cfg)。該函數(shù)得到由fd指向的終端的配置參數(shù),并將它們保存于termios結(jié)構(gòu)變量old_cfg中。該函數(shù)還可以測(cè)試配置是否正確、該串口是否可用等。若調(diào)用成功,函數(shù)返回值為0,若調(diào)用失敗,函數(shù)返回值為1
if(tcgetattr(fd,&old_cfg)!=0){ perror("tcgetattr"); return-1; }2.4嵌入式Linux串口應(yīng)用編程67
2.4.2串口配置設(shè)置工作模式調(diào)用cfmakeraw()函數(shù)可以將終端設(shè)置為原始模式,在后面的實(shí)例中,采用原始模式進(jìn)行串口數(shù)據(jù)通信。
cfmakeraw(&new_cfg);2.4嵌入式Linux串口應(yīng)用編程68
2.4.2串口配置設(shè)置波特率設(shè)置波特率有專門的函數(shù),用戶不能直接通過位掩碼來操作。設(shè)置波特率的主要函數(shù)有:cfsetispeed()和cfsetospeed()。cfsetispeed(&new_cfg,B115200);cfsetospeed(&new_cfg,B115200);2.4嵌入式Linux串口應(yīng)用編程69
2.4.2串口配置設(shè)置字符大小與設(shè)置波特率不同,設(shè)置字符大小并沒有現(xiàn)成可用的函數(shù),需要用位掩碼。一般首先去除數(shù)據(jù)位中的位掩碼,再重新按要求設(shè)置
new_cfg.c_cflag&=~CSIZE;/*用數(shù)據(jù)位掩碼清空數(shù)據(jù)位設(shè)置*/
new_cfg.c_cflag|=CS8;2.4嵌入式Linux串口應(yīng)用編程70
2.4.2串口配置設(shè)置奇偶校驗(yàn)位設(shè)置奇偶校驗(yàn)位需要用到termios中的兩個(gè)成員:c_cflag和c_iflag。首先要激活c_cflag中的校驗(yàn)位使能標(biāo)志PARENB和是否要進(jìn)行校驗(yàn),這樣會(huì)對(duì)輸出數(shù)據(jù)產(chǎn)生校驗(yàn)位,而輸入數(shù)據(jù)進(jìn)行校驗(yàn)檢查。同時(shí)還要激活c_iflag中的對(duì)于輸入數(shù)據(jù)的奇偶校驗(yàn)使能(INPCK)。奇校驗(yàn)
new_cfg.c_cflag|=(PARODD|PARENB); new_cfg.c_iflag|=INPCK;偶校驗(yàn)
new_cfg.c_cflag|=PARENB; new_cfg.c_cflag&=~PARODD; new_cfg.c_iflag|=INPCK;2.4嵌入式Linux串口應(yīng)用編程71
2.4.2串口配置設(shè)置停止位設(shè)置停止位是通過激活c_cflag中的CSTOPB而實(shí)現(xiàn)的。若停止位為一個(gè),則清除CSTOPB,若停止位為兩個(gè),則激活CSTOPB。
new_cfg.c_cflag&=~CSTOPB;//將停止位設(shè)置為一個(gè)比特
new_cfg.c_cflag|=CSTOPB; //將停止位設(shè)置為兩個(gè)比特2.4嵌入式Linux串口應(yīng)用編程72
2.4.2串口配置設(shè)置最少字符和等待時(shí)間在對(duì)接收字符和等待時(shí)間沒有特別要求的情況下,可以將其設(shè)置為0,則在任何情況下read()函數(shù)立即返回,此時(shí)串口操作會(huì)設(shè)置為非阻塞方式。
new_cfg.c_cc[VTIME]=0; new_cfg.c_cc[VMIN]=0;2.4嵌入式Linux串口應(yīng)用編程73
2.4.2串口配置清除串口緩沖串口在重新設(shè)置之前,需要對(duì)當(dāng)前的串口設(shè)備進(jìn)行適當(dāng)?shù)奶幚?,這時(shí)就可調(diào)用在<termios.h>中聲明的tcdrain()、tcflow()、tcflush()等函數(shù)來處理目前串口緩沖中的數(shù)據(jù)。
inttcdrain(intfd);/*使程序阻塞,直到輸出緩沖區(qū)的數(shù)據(jù)全部發(fā)送完畢*/
inttcflow(intfd,intaction);/*用于暫?;蛑匦麻_始輸出*/
inttcflush(intfd,intqueue_selector);/*用于清空輸入/輸出緩沖區(qū)*/2.4嵌入式Linux串口應(yīng)用編程74
2.4.2串口配置清除串口緩沖
tcflush()函數(shù),對(duì)于在緩沖區(qū)中的尚未傳輸?shù)臄?shù)據(jù),或者收到的但是尚未讀取的數(shù)據(jù),其處理方法取決于queue_selector的值,它可能的取值有以下幾種。 TCIFLUSH:對(duì)接收到而未被讀取的數(shù)據(jù)進(jìn)行清空處理。 TCOFLUSH:對(duì)尚未傳送成功的輸出數(shù)據(jù)進(jìn)行清空處理。 TCIOFLUSH:包括前兩種功能,即對(duì)尚未處理的輸入輸出數(shù)據(jù)進(jìn)行清空處理。示例:tcflush(fd,TCIFLUSH);
2.4嵌入式Linux串口應(yīng)用編程75
2.4.2串口配置激活配置在完成全部串口配置之后,要激活剛才的配置并使配置生效。這里用到的函數(shù)是tcsetattr(),它的函數(shù)原型是:tcsetattr(intfd,intoptional_actions,conststructtermios*termios_p); 其中參數(shù)termios_p是termios類型的新配置變量。 參數(shù)optional_actions可能的取值有以下三種: TCSANOW:配置的修改立即生效。 TCSADRAIN:配置的修改在所有寫入fd的輸出都傳輸完畢之后生效。 TCSAFLUSH:所有已接受但未讀入的輸入都將在修改生效之前被丟棄。
2.4嵌入式Linux串口應(yīng)用編程76
2.4.2串口配置串口配置示例intset_com_config(intfd,intbaud_rate, intdata_bits,charparity,intstop_bits){ structtermiosnew_cfg,old_cfg; intspeed; if(tcgetattr(fd,&old_cfg)!=0) { perror("tcgetattr"); return-1; }
new_cfg=old_cfg;
cfmakeraw(&new_cfg);/*配置為原始模式*/
2.4嵌入式Linux串口應(yīng)用編程77
2.4.2串口配置串口配置示例 switch(baud_rate) { case2400: { speed=B2400; } ……
default: case115200: { speed=B115200; } break; }
cfsetispeed(&new_cfg,speed); cfsetospeed(&new_cfg,speed);2.4嵌入式Linux串口應(yīng)用編程78
2.4.2串口配置串口配置示例
new_cfg.c_cflag&=~CSIZE; switch(data_bits)/*設(shè)置數(shù)據(jù)位*/ { case7: {
new_cfg.c_cflag|=CS7; } break; default: case8: {
new_cfg.c_cflag|=CS8; } break; }2.4嵌入式Linux串口應(yīng)用編程79
2.4.2串口配置串口配置示例 switch(parity)/*設(shè)置奇偶校驗(yàn)位*/ { default: case'n': case'N': {
new_cfg.c_cflag&=~PARENB; new_cfg.c_iflag&=~INPCK;
} break; case'o': case'O': {
new_cfg.c_cflag|=(PARODD|PARENB); new_cfg.c_iflag|=INPCK;
} break;2.4嵌入式Linux串口應(yīng)用編程80
2.4.2串口配置串口配置示例 case'e': case'E': { new_cfg.c_cflag|=PARENB; new_cfg.c_cflag&=~PARODD; new_cfg.c_iflag|=INPCK; } break; }2.4嵌入式Linux串口應(yīng)用編程81
2.4.2串口配置串口配置示例 switch(stop_bits)/*設(shè)置停止位*/ { default: case1: {
new_cfg.c_cflag&=~CSTOPB; } break; case2: {
new_cfg.c_cflag|=CSTOPB; } }2.4嵌入式Linux串口應(yīng)用編程82
2.4.2串口配置串口配置示例 /*設(shè)置等待時(shí)間和最小接收字符*/
new_cfg.c_cc[VTIME]=0; new_cfg.c_cc[VMIN]=1; tcflush(fd,TCIFLUSH);/*處理未接收字符*/ if((tcsetattr(fd,TCSANOW,&new_cfg))!=0)/*激活新配置*/ { perror("tcsetattr"); return-1; } return0;}2.4嵌入式Linux串口應(yīng)用編程83
2.4.3串口使用打開串口使用open函數(shù)打開串口fd=open(“/dev/ttyS0”,O_RDWR|O_NOCTTY|O_NDELAY);O_NOCTTY:使打開的文件不成為這個(gè)進(jìn)程的控制終端O_NDELAY:設(shè)置為非阻塞方式。通知Linux系統(tǒng),這個(gè)程序不關(guān)心DCD信號(hào)線所處的狀態(tài)(端口的另一端是否激活或者停止)。接下來可恢復(fù)串口為阻塞狀態(tài),用于等待串口數(shù)據(jù)的讀入:fcntl(fd,F_SETFL,0);2.4嵌入式Linux串口應(yīng)用編程84
2.4.3串口使用打開串口intopen_port(intcom_port){ intfd;#if(COM_TYPE==GNR_COM)/*使用普通串口*/ char*dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};#else/*使用USB轉(zhuǎn)串口*/ char*dev[]={"/dev/ttyUSB0","/dev/ttyUSB1","/dev/ttyUSB2"};#endif if((com_port<0)||(com_port>MAX_COM_NUM)) { return-1; }
2.4嵌入式Linux串口應(yīng)用編程85
2.4.3串口使用打開串口
/*打開串口*/ fd=open(dev[com_port-1],O_RDWR|O_NOCTTY|O_NDELAY); if(fd<0) { perror("openserialport"); return(-1); }
if(fcntl(fd,F_SETFL,0)<0)/*恢復(fù)串口為阻塞狀態(tài)*/ { perror("fcntlF_SETFL\n"); }
returnfd;}2.4嵌入式Linux串口應(yīng)用編程86
2.4.3串口使用讀寫串口使用read()、write()函數(shù)進(jìn)行串口的讀寫操作write(fd,buff,strlen(buff));read(fd,buff,BUFFER_SIZE);實(shí)例:寫串口的程序在宿主機(jī)上運(yùn)行,讀串口的程序在目標(biāo)板上運(yùn)行,用戶在宿主機(jī)上輸入信息,通過寫/讀程序發(fā)送到目標(biāo)板上。
2.4嵌入式Linux串口應(yīng)用編程87
2.4.3串口使用寫串口程序
/*com_writer.c*/#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<termios.h>#include<fcntl.h>#defineHOST_COM_PORT1#defineBUFFER_SIZE1024#defineMAX_COM_NUM4#include“uart_api.h”
/*串口設(shè)置和打開函數(shù)*/2.4嵌入式Linux串口應(yīng)用編程88
2.4.3串口使用寫串口程序
intmain(void){ intfd; charbuff[BUFFER_SIZE]; if((fd=open_port(HOST_COM_PORT))<0)/*打開串口*/ { perror("open_port"); return1; } if(set_com_config(fd,115200,8,'N',1)<0)/*配置串口*/ { perror("set_com_config"); return1; }2.4嵌入式Linux串口應(yīng)用編程89
2.4.3串口使用寫串口程序
do { printf("Inputsomewords(enter'quit'toexit):");
memset(buff,0,BUFFER_SIZE); if(fgets(buff,BUFFER_SIZE,stdin)==NULL) { perror("fgets"); break; } write(fd,buff,strlen(buff)); }while(strncmp(buff,"quit",4)); close(fd); return0;}2.4嵌入式Linux串口應(yīng)用編程90
2.4.3串口使用讀串口程序
/*com_reader.c*/#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<termios.h>#include<fcntl.h>#defineTARGET_COM_PORT1#defineBUFFER_SIZE1024#defineMAX_COM_NUM4#include"uart_api.h"2.4嵌入式Linux串口應(yīng)用編程91
2.4.3串口使用讀串口程序
intmain(void){ intfd; charbuff[BUFFER_SIZE];
if((fd=open_port(TARGET_COM_PORT))<0)/*打開串口*/ { perror("open_port"); return1; } if(set_com_config(fd,115200,8,'N',1)<0)/*配置串口*/ { perror("set_com_config"); return1; }2.4嵌入式Linux串口應(yīng)用編程92
2.4.3串口使用讀串口程序
do {
memset(buff,0,BUFFER_SIZE); if(read(fd,buff,BUFFER_SIZE)>0) { printf("Thereceivedwordsare:%s",buff); } }while(strncmp(buff,"quit",4)); close(fd); return0;}2.4嵌入式Linux串口應(yīng)用編程93
使用底層I/OAPI函數(shù)進(jìn)行文件操作時(shí),Linux必須從用戶態(tài)切換到內(nèi)核態(tài),執(zhí)行相應(yīng)的請(qǐng)求,然后再返回到用戶態(tài)。為提高程序的效率,應(yīng)盡量減少系統(tǒng)調(diào)用的次數(shù)。標(biāo)準(zhǔn)I/O又稱為高級(jí)磁盤I/O,在文件I/O的基礎(chǔ)上進(jìn)行了封裝,目的是盡可能減少使用read()、write()等系統(tǒng)調(diào)用的數(shù)量。2.5標(biāo)準(zhǔn)I/O編程94
標(biāo)準(zhǔn)I/O提供了3種類型的緩沖存儲(chǔ):全緩沖:當(dāng)填滿標(biāo)準(zhǔn)I/O緩存后才進(jìn)行實(shí)際的I/O操作。對(duì)駐留在磁盤上的文件訪問通常是由標(biāo)準(zhǔn)I/O實(shí)施全緩沖的;行緩沖:當(dāng)在輸入和輸出中遇到行結(jié)束符時(shí),標(biāo)準(zhǔn)I/O庫執(zhí)行I/O操作。例如標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出。不帶緩沖:不對(duì)字符進(jìn)行緩沖。如果標(biāo)準(zhǔn)I/O函數(shù)寫若干字符到不帶緩沖的流中,則相當(dāng)于用write系統(tǒng)調(diào)用將這些字符寫到打開的文件上。2.5標(biāo)準(zhǔn)I/O編程2.5標(biāo)準(zhǔn)I/O編程文件指針標(biāo)準(zhǔn)I/O為每個(gè)被使用的文件在內(nèi)存中開辟一個(gè)區(qū)域,用來存放文件的相關(guān)信息。這些信息被保存在一個(gè)由系統(tǒng)定義的結(jié)構(gòu)體類型FILE中。在標(biāo)準(zhǔn)I/O中,流(stream)用FILE*來描述,所有的操作都是圍繞流來進(jìn)行的。FILE的具體定義如下:in<stdio.h>typedefstruct_IO_FILEFILE2.5標(biāo)準(zhǔn)I/O編程文件指針
in<libio.h>struct_IO_FILE{int_flags;……int_fileno;……}
FILE中的成員_fileno保存的就是流所對(duì)應(yīng)的文件描述符。標(biāo)準(zhǔn)I/O庫中預(yù)定義了3個(gè)流:標(biāo)準(zhǔn)輸入(stdin)、標(biāo)準(zhǔn)輸出(stdout)和標(biāo)準(zhǔn)錯(cuò)誤(stderr)。97
2.5.1基本操作1.打開文件
打開文件有三個(gè)標(biāo)準(zhǔn)函數(shù),分別為:fopen()、fdopen()和freopen()。它們可以以不同的模式打開,但都返回一個(gè)指向FILE的指針,該指針指向?qū)?yīng)的I/O流。此后,對(duì)文件的讀寫都是通過這個(gè)FILE指針來進(jìn)行。fopen()可以指定打開文件的路徑和模式;fdopen()可以指定打開的文件描述符和模式;freopen()可以指定打開的文件、模式以及特定的I/O 流。2.5標(biāo)準(zhǔn)I/O編程98
2.5.1基本操作1.打開文件
fopen函數(shù):Openafileandcreateanewstreamforit.
2.5標(biāo)準(zhǔn)I/O編程99
2.5.1基本操作1.打開文件
mode類似于open()函數(shù)中的flag,可以定義打開文件的訪問權(quán)限等,下面為mode的各種取值:其中“b”表示打開的文件為二進(jìn)制文件,而非純文本文件。
2.5標(biāo)準(zhǔn)I/O編程100
2.5.1基本操作1.打開文件
fdopen()可以指定打開的文件描述符和模式。Createanewstreamthatreferstoanexistingsystemfiledescriptor.
mode取值同fopen
2.5標(biāo)準(zhǔn)I/O編程101
2.5.1基本操作1.打開文件
freopen()除可指定打開的文件、模式外,還可指定特定的I/O流。
Openafile,replacinganexistingstreamwithit.
mode取值同fopen
2.5標(biāo)準(zhǔn)I/O編程102
2.5.1基本操作2.關(guān)閉文件 關(guān)閉標(biāo)準(zhǔn)流文件的函數(shù)為fclose(),該函數(shù)將緩沖區(qū)內(nèi)的數(shù)據(jù)全部寫入到文件中,并釋放系統(tǒng)所提供的文件資源。
fclose()函數(shù)格式:2.5標(biāo)準(zhǔn)I/O編程2.5標(biāo)準(zhǔn)I/O編程2.5.2讀寫操作1.按字符讀/寫文件一次讀取或?qū)懭胍粋€(gè)字符,如果流是帶緩存的,由I/O函數(shù)來處理緩存。(1)函數(shù)說明在文件打開之后,可對(duì)文件流進(jìn)行讀寫等操作。其中讀文件的函數(shù)為fgetc/getc/getchar,寫文件的函數(shù)為fputc/putc/putchar。(2)函數(shù)格式頭文件#include<stdio.h>2.5標(biāo)準(zhǔn)I/O編程2.5.2讀寫操作1.按字符讀/寫文件函數(shù)原型intfgetc(FILE*stream); /*從指定的文件流中讀取一個(gè)字符*/intgetc(FILE*stream);/*從指定的文件流中讀取一個(gè)字符*/intgetchar(void);/*從標(biāo)準(zhǔn)輸入讀取一個(gè)字符*/intfputc(intc,FILE*stream);/*往指定的文件流寫入一個(gè)字符*/intputc(intc,FILE*stream);/*往指定的文件流寫入一個(gè)字符*/intputchar(intc);/*往標(biāo)準(zhǔn)輸出寫入一個(gè)字符*/
函數(shù)返回值成功:讀取成功時(shí)返回讀取的字符/寫入成功時(shí)返回0失敗:EOF2.5標(biāo)準(zhǔn)I/O編程2.按行讀/寫文件
一次讀取或?qū)懭胍恍?,通常以換行符作為一行的結(jié)束。(1)函數(shù)說明讀文件的函數(shù)為fgets,寫文件的函數(shù)為fputs/puts。(2)函數(shù)格式頭文件#include<stdio.h>
函數(shù)原型char*fgets(char*s,intn,FILE*stream);/*從流stream中最多讀取n-1個(gè)字符存放到緩沖區(qū)s*/intfputs(constchar*s,FILE*stream);/*將字符串s輸出到流stream*/intputs(constchar*s);/*將字符串s輸出到標(biāo)準(zhǔn)輸出*/2.5.2讀寫操作2.5標(biāo)準(zhǔn)I/O編程2.按行讀/寫文件函數(shù)返回值fgets(成功:緩沖區(qū)的地址,即s的值/失?。篘ULL)fputs(成功:1/失?。篍OF)puts(成功:字符串的長(zhǎng)度加1/失敗:EOF)(3)函數(shù)調(diào)用實(shí)例charbuf[20];fgets(buf,20,stdin);//從標(biāo)準(zhǔn)輸入最多讀取19個(gè)字符存放到緩沖區(qū)buf里fputs(“Hellotheworld“,stdout);//將字符串Hellotheworld寫到標(biāo)準(zhǔn)輸出puts(“Hellotheworld“);//將字符串Hellotheworld寫到標(biāo)準(zhǔn)輸出后再輸出換行符2.5標(biāo)準(zhǔn)I/O編程3.按指定格式讀/寫文件
以指定的格式一次從文件中讀取或?qū)懭肴舾蓚€(gè)對(duì)象,通常用來處理二進(jìn)制文件。(1)函數(shù)說明讀文件的函數(shù)為fread,寫文件的函數(shù)為fwrite。(2)函數(shù)格式頭文件#include<stdio.h>2.5標(biāo)準(zhǔn)I/O編程3.按指定格式讀/寫文件
函數(shù)原型size_tfread/fwrite(void*ptr,/*存放讀取/寫入記錄的緩沖區(qū)*/
size_tsize,/*讀取/寫入的記錄大小*/
size_tnmemb,/*讀取/寫入的記錄數(shù)*/
FILE*stream);/*要讀取/寫入的文件流*/
函數(shù)返回值成功:返回實(shí)際讀取/寫入的記錄數(shù)目失?。篍OF2.5標(biāo)準(zhǔn)I/O編程3.按指定格式讀/寫文件(3)函數(shù)調(diào)用實(shí)例FILE*stream;intarray[]={1,2,3,4,5,6,7,8};/*首先使用fopen以只寫方式打開文件,之后再調(diào)用fwrite寫入文件*/stream=fopen("data","w");if(stream==NULL)exit(-1);fwrite(array,sizeof(int),sizeof(array)/sizeof(int),stream);fclose(stream);
2.5標(biāo)準(zhǔn)I/O編程4.刷新流(1)函數(shù)說明強(qiáng)制刷新一個(gè)流,使該流所有未寫的緩沖區(qū)數(shù)據(jù)寫入到實(shí)際的流中(2)函數(shù)格式頭文件#include<stdio.h>
函數(shù)原型intfflush(FILE*stream);
函數(shù)返回值成功:0失敗:-12.5標(biāo)準(zhǔn)I/O編程4.刷新流(3)函數(shù)調(diào)用實(shí)例printf(“stdoutisline-buffered“);/*因?yàn)闃?biāo)準(zhǔn)輸出是行緩沖,所以沒有遇到’\n’之前輸出的內(nèi)容先保存在標(biāo)準(zhǔn)輸出緩沖區(qū)里*/sleep(2);//進(jìn)程睡眠2秒鐘fflush(stdout);//刷新標(biāo)準(zhǔn)輸出流,緩沖區(qū)的內(nèi)容被送到標(biāo)準(zhǔn)輸出2.5標(biāo)準(zhǔn)I/O編程5.文件定位
(1)函數(shù)說明文件中有個(gè)位置指針,指向當(dāng)前讀寫的位置。fseek/rewind可以改變文件的位置指針,ftell返回流式文件的當(dāng)前位置。(2)函數(shù)格式頭文件#include<stdio.h>
函數(shù)原型voidrewind(FILE*stream);//使位置指針重新指向文件的開始intfseek(FILE*stream,
longoffset,//位移量,以起始點(diǎn)為基準(zhǔn)移動(dòng)的字節(jié)數(shù)
intwhence);//起始點(diǎn),SEEK_SET/SEEK_CUR/SEEK_ENDlongftell(FILE*stream);2.5標(biāo)準(zhǔn)I/O編程5.文件定位
函數(shù)返回值fseek(成功:0 失敗:-1)ftell(成功:文件當(dāng)前位置 失?。?1L)(3)函數(shù)調(diào)用實(shí)例FILE*fp=fopen(“data“,“r+“);//以讀寫方式打開文件inti=10;
if(fp==NULL)exit(-1);fseek(fp,0L,SEEK_END);//將文件指針定位到文件末尾fwrite(&i,4,1,fp);//寫入新的內(nèi)容fclose(fp);114
6.格式化輸入/輸出
2.5標(biāo)準(zhǔn)I/O編程115
6.格式化輸入/輸出
2.5標(biāo)準(zhǔn)I/O編程116
系統(tǒng)調(diào)用、用戶(應(yīng)用)編程接口(API)和系統(tǒng)命令的聯(lián)系和區(qū)別。虛擬文件系統(tǒng)(VFS)及文件描述符。底層文件I/O操作(open,close,read,write,lseek等函數(shù))文件鎖(fcntl函數(shù))多路復(fù)用(I/O處理的5種模型,poll函數(shù)的使用)嵌入式Linux串口編程(structtermios數(shù)據(jù)結(jié)構(gòu),tcgetattr,tcsetattr,fcntl,isatty函數(shù))標(biāo)準(zhǔn)I/O(打開/關(guān)閉文件、字符I/O、行I/O、格式化I/O)小結(jié)117
文件的讀寫與上鎖實(shí)驗(yàn)?zāi)康耐ㄟ^編寫文件讀寫及上鎖的程序,進(jìn)一步熟悉Linux中文件I/O相關(guān)的應(yīng)用開發(fā),并且熟練掌握open()、read()、write()、fcntl()等函數(shù)的使用。實(shí)驗(yàn)內(nèi)容在Linux中FIFO是一種進(jìn)程之間的管道通信機(jī)制。Linux支持完整的FIFO通信機(jī)制,本實(shí)驗(yàn)通過使用文件操作,仿真FIFO(先進(jìn)先出)結(jié)構(gòu)以及生產(chǎn)者-消費(fèi)者運(yùn)行模型。2.6實(shí)驗(yàn)內(nèi)容118
文件的讀寫與上鎖本實(shí)驗(yàn)中需要打開兩個(gè)虛擬終端,分別運(yùn)行生產(chǎn)者程序(producer)和消費(fèi)者程序(customer)。此時(shí)兩個(gè)進(jìn)程同時(shí)對(duì)同一個(gè)文件進(jìn)行讀寫操作。因?yàn)檫@個(gè)文件是臨界資源,所以可以使用文件鎖機(jī)制來保證兩個(gè)進(jìn)程對(duì)文件的訪問都是原子操作。先啟動(dòng)生產(chǎn)者進(jìn)程,它負(fù)責(zé)創(chuàng)建仿真FIFO結(jié)構(gòu)的文件(其實(shí)是一個(gè)普通文件)并投入生產(chǎn),就是按照給定的時(shí)間間隔,向FIFO文件寫入自動(dòng)生成的字符(在程序中用宏定義選擇使用數(shù)字還是使用英文字符),生產(chǎn)周期以及要生產(chǎn)的資源數(shù)通過參數(shù)傳遞給進(jìn)程(默認(rèn)生產(chǎn)周期為1秒,要生產(chǎn)的資源總數(shù)為10個(gè)字符,顯然默認(rèn)生產(chǎn)總時(shí)間為10秒鐘)。后啟動(dòng)的消費(fèi)者進(jìn)程按照給定的數(shù)目進(jìn)行消費(fèi),首先從文件中讀取相應(yīng)數(shù)目的字符并在屏幕上顯示,然后從文件中刪除剛才消費(fèi)過的數(shù)據(jù)。為了仿真FIFO結(jié)構(gòu),此時(shí)需要使用兩次拷貝來實(shí)現(xiàn)文件內(nèi)容的偏移。每次消費(fèi)的資源數(shù)通過參數(shù)傳遞給進(jìn)程,默認(rèn)值為10個(gè)字符。2.6實(shí)驗(yàn)內(nèi)容119
文件的讀寫與上鎖——生產(chǎn)者源程序/*producer.c*/#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>#include<fcntl.h>#include“l(fā)ock_set.c"2.6實(shí)驗(yàn)內(nèi)容120
文件的讀寫與上鎖——生產(chǎn)者源程序constchar*fifo_file="./myfifo"; /*仿真FIFO文件名*/charbuff[MAXLEN]; /*緩沖區(qū)*/2.6實(shí)驗(yàn)內(nèi)容121
文件的讀寫與上鎖——生產(chǎn)者源程序constchar*fifo_file="./myfifo"; /*仿真FIFO文件名*/charbuff[MAXLEN]; /*緩沖區(qū)*/intproduct(void){ intfd; staticunsignedintcounter=0;
/*打開仿真FIFO文件*/ fd=open(fifo_file,O_CREAT|O_RDWR|O_APPEND,0644)2.6實(shí)驗(yàn)內(nèi)容122
文件的讀寫與上鎖——生產(chǎn)者源程
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 體育賽事招投標(biāo)及合同管理標(biāo)準(zhǔn)
- 商務(wù)中心辦公室租賃協(xié)議范本
- 2024版高速公路運(yùn)輸合同書
- 藝術(shù)品鑒定師聘任合同證書
- 文化設(shè)施石材施工合同
- 2024租賃物維修與保養(yǎng)服務(wù)合同
- 2024甲方乙方關(guān)于房地產(chǎn)開發(fā)的合同
- 二零二五年度特種鋼板租賃及運(yùn)輸服務(wù)合同3篇
- 二零二五年度二樓商鋪?zhàn)赓U與顧客忠誠度提升合同2篇
- 2024版酒店早餐服務(wù)外包協(xié)議樣本版B版
- 家居保潔課件
- 換電站(充電樁)安全風(fēng)險(xiǎn)告知
- 經(jīng)營(yíng)性房屋租賃項(xiàng)目投標(biāo)方案(技術(shù)標(biāo))
- 入戶調(diào)查合同范本
- 七年級(jí)道法上冊(cè)第一學(xué)期期末綜合測(cè)試卷(人教版 2024年秋)
- 上海上海市皮膚病醫(yī)院工作人員招聘筆試歷年典型考題及考點(diǎn)附答案解析
- 標(biāo)桿地產(chǎn)五星級(jí)酒店精裝修標(biāo)準(zhǔn)
- DZ∕T 0153-2014 物化探工程測(cè)量規(guī)范(正式版)
- 商業(yè)空間設(shè)計(jì)(高職環(huán)境藝術(shù)設(shè)計(jì)專業(yè)和室內(nèi)設(shè)計(jì)專業(yè))全套教學(xué)課件
- 廣東省廣州市名校聯(lián)盟重點(diǎn)名校2024屆中考化學(xué)全真模擬試卷含解析
- 大學(xué)校園交通安全現(xiàn)狀調(diào)查分析
評(píng)論
0/150
提交評(píng)論