通信原理课设(gec6818) 001:环境配置+文件操作
目录
2、在一个1.txt的前面4个字节放了一个千位数,以 %d的形式输出它的两倍
3、写一个简单的学生信息录入系统:学生信息包括:姓名 学号 年龄 地址 从终端输入学生信息写入到文件里面保存,一个学生一行数据
简单记录一下为期两周的通信原理课设,本次课设采用交叉编译,所谓交叉编译是指一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码。简而言之即在一个平台上生成另一个平台上的可执行代码。此次课设的代码先在ubuntu里面使用arm-linux-gcc编译,再利用SecureCRT将编译好的文件传输到开发板上。
Securecrt网盘链接:
链接:https://pan.baidu.com/s/1pnA4HHJybezT-zPxCD3_Uw?pwd=scrt
提取码:scrt
上课之前,自己先准备了一点基础知识,主要是ubuntu的基本命令,更快上手,还挺有用的:
常用终端命令
ls 查看当前文件夹下的内容 -a:所有的 -l:表示长列表形式
pwd (print work directory)查看当前所在文件夹
cd (change directory) 切换文件夹
touch 如果文件不存在,新建文件
mkdir (make directory) 创建目录
rm 删除指定的文件夹
clear 清屏
终端命令格式
command [-optinons] [parameter]
command :命令名
-optinons:选项,用来对命令进行控制,可省略
parameter:传递给命令的参数
[]代表可选
查阅命令
command --help : 显示command命令的帮助信息
man command : 查阅命令手册
(command替换成具体的命令)
man 页数 函数接口
实用技巧(特别有用尤其电脑分屏的时候)
ctrl+shift+= 放大终端窗口的字体显示
ctrl+- 缩小终端窗口的字体显示
ctrl+c 退出选择,另起一行
编译
gcc编译c文件,g++编译c++文件。
当你的程序只有一个源文件时,直接就可以用gcc命令编译它。但是当你的程序包含很多个源文件时,用gcc命令逐个去编译时,你就很容易混乱而且工作量大.
所以出现了make工具!make工具可以看成是一个智能的批处理工具,它本身并没有编译和链接的功能,而是用类似于批处理的方式—通过调用makefile文件中用户指定的命令来进行编译和链接的。
makefile在一些简单的工程完全可以人工手下,但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改。
这时候就出现了Cmake这个工具,cmake就可以更加简单的生成makefile文件给上面那个make用。当然cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,你不用再自己去修改了。可是cmake根据什么生成makefile呢?它又要根据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。
一、设置环境
1、安装VMware-player-full-17.0.2-21581411
2、设置虚拟机共享文件夹
由于我们的开发是在win里面,因此我们写的代码要放在共享文件夹里面linux才可以看得到。
菜单栏选择虚拟机设置-> 选项 -> 共享文件夹 -> 总是启动 -> 添加 -> 下一步-> 浏览 -> 选择自己喜欢的文件夹(最好是不带中文以及空格的)-> 确定 -> 下一步 -> 完成 -> 确定。
打开终端(ctrl + alt + t),切换到我们的共享目录:
cd /mnt/hgfs/你的共享目录名字
二、学会操作文件
Linux -> 是世界上面运用做广的系统,它是一个开源的系统,这个系统是继承于unix。Linux中“everything is file !!!”,也就是一切皆文件。操作系统操作文件即可,因此系统的操作就离不开文件io。
正如把大象装进冰箱需要三步: 1 打开冰箱门 2 将大象装进去 3 关闭冰箱门
所以操作文件也类似上述三步: 1 打开文件 2 读/写文件 3 关闭文件
(特别重要,之后的文件操作都是基于这三步)
1、打开文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);//打开文件
int open(const char *pathname, int flags, mode_t mode)//打开或者创建一个文件
int creat(const char *pathname, mode_t mode);//创建一个文件
参数解释:
pathname:路径名 ,这个参数的原型是一个char *字符串
相对路径: "./1.txt"、 "../2.txt"(.是相对于当前目录;..是相当于上级目录或者
叫做父目录)
绝对路径:"/mnt/hgfs/share/1.txt"
flags: 打开文件的一些标志 用位域表示这里用宏去搞定这些功能的问题
如果有需求多个功能同时打开,那么直接用 | 按位或
下面的三个标志任选其一,这个标记是必须要给的
O_RDONLY :只读
O_WRONLY: 只写
O_RDWR: 读写
下面的标记根据自己的需求去选择
O_CREAT:创建标记:如果你给这个创建标记 第三个参数就要给了,给了这个标 记表示此文件存在即打开,不存在则创建并打开
O_NONBLOCK:非阻塞打开这个文件 ,文件打开默认是阻塞的
O_APPEND:追加标记, 打开文件光标默认在开头
O_TRUNC:截短标记,将内容清空
mode:权限 linux里面的权限分为三个部分:用户 组用户 其它用户
S_IRWXU 用户可读可写可执行
S_IRUSR 用户只读
....
S_IRWXG 组户可读可写可执行
.....
S_IRWXO 其它用户可读可写可执行
......
我们可以使用8进制去表示一个权限:常用的是:0664
返回值:
成功返回一个大于等于0的整数(实际上是 >= 3)
我们的进程在一启动的时候操作系统就会为这个程序打开三个文件
1 标准的输入 -> 0
2 标准的输出 -> 1
3 标准的出错 -> 2
返回给你的这个整数是一个数组(进程文件表项)的下标
这个整数我们有一个名词去描述 ---- 文件描述符(fd)
后续对于文件的操作都是基于这个fd的
失败返回-1,同时errno被设置,perror可以解析一个系统错误
perror:
#include <stdio.h> void perror(const char *s);
s:程序员设计的一个标记,该接口调用会打印出系统的错误信息。
使用方法:
int fd = open(); if(-1 == fd)//马上进行错误判断 { perror("发生错误:"); }
2、读/写文件
2.1 读文件
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数解释:
fd:文件描述符
buf:我们读到的内容你要放在一个内存才能操作,这个buf就是这块内存的首地址
c语言是没有边界检查的,因此我们要时刻的注意是否会越界的问题
程序员开辟内存一般是在栈空间或者堆空间
栈:在代码块里面开辟变量或者数组,代码块执行完毕,这块空间会被释放
堆:动态内存分配:malloc、calloc、realloc;在堆上面开辟的内存是不会主动释放的count: 你要读取多少个字节 (>= 0)
返回值:成功返回实际读到的字节数 <= count
失败返回-1,同时errno被设置
文件内容的读取都是从光标位置进行的,每读写一个字节,光标就会自动往后面偏移一个。
2.2 写文件
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数解释:
fd:文件描述符
buf:你要写什么样子的内容到我们的文件,实际上就是一个内存,里面存储我们要写入的 内容count:我们要写入多少个字节
返回值:成功返回实际写入的字节数 <= count
失败返回-1,同时errno被设置
3、关闭文件
#include <unistd.h>
int close(int fd);
close - 关闭一个文件描述符
三、练习
1、打开一个文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
//打开一个文件
int fd=open("./1.txt",O_RDWR);
if(-1==fd)
{
perror("open 1.txt error");
return -1;
}
printf("open 1.txt sucessful!\r\n");
printf("test");
return 0;
}
2、在一个1.txt的前面4个字节放了一个千位数,以 %d的形式输出它的两倍
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
//1、打开一个文件
int fd=open("./1.txt",O_RDWR);
int a,b,c,d,e;
int A[5];
if(-1==fd)
{
perror("open 1.txt error");
return -1;
}
//2、读取文件内容
char buf[1025] = {0}; //在栈上开辟1024字节
int r = read(fd,buf,1024);//1025是为了\0,读取1.txt的内容并存放在了buf
//以%d的形式输出两倍,前四个字节
if(-1 == r)
{
perror("read error");
return -2;
}
printf("%c\n",buf[0]);
printf("%c\n",buf[1]);
printf("%c\n",buf[2]);
printf("%c\n",buf[3]);
a = (buf[0]-'0')*1000;
b = (buf[1]-'0')*100;
c = (buf[2]-'0')*10;
d = (buf[3]-'0')*1;
e = a+b+c+d;
printf("%d\n",e*2);
//3、关闭文件
close(fd);
return 0;
}
3、写一个简单的学生信息录入系统:学生信息包括:姓名 学号 年龄 地址
从终端输入学生信息写入到文件里面保存,一个学生一行数据
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
//全局的学生信息文件
int fd_stu = -1;
//初始化文件 这个文件是固定的
void StudentFileInit(void)
{
fd_stu = open("./student.txt",O_RDWR | O_CREAT,0664);
if(-1 == fd_stu)
{
perror("open error");
exit(2);
}
}
//将文件销毁
void DestoryStudentFile(void)
{
close(fd_stu);
}
//往一个文件里面写入一个字符串
void WriteStringToFile(int fd,const char * str)
{
write(fd,str,strlen(str));
}
//存储学生信息
void SaveStudentMassage(void)
{
StudentFileInit();//将文件打开
char name[64];
int age;
int id;
char addr[128];
while(1)//录到sb250就结束输入
{
//获取学生信息
printf("请输入学生姓名(sb250结束):");
fflush(stdout);
scanf("%s",name);
if(!strcmp(name,"sb250"))
{
break;
}
//printf("name = %s\n",name);
printf("请输入学生学号:");
fflush(stdout);
scanf("%d",&id);
printf("请输入学生年龄:");
fflush(stdout);
scanf("%d",&age);
printf("请输入学生地址:");
fflush(stdout);
scanf("%s",addr);
char buf[1024];
sprintf(buf,"%d %s %d %s\n",id,name,age,addr);
WriteStringToFile(fd_stu,buf);
}
DestoryStudentFile();
}
//缓冲区的概念测试
void hehe(void)
{
int i;
for(i = 0;i < 1024;i++)
{
printf("A");
}
//我们也可以强制让它刷新
fflush(stdout);
while(1);
}
//FILE * stdout = fopen
int main(int argc,char * argv[])
{
if(argc < 3)
{
printf("参数不对\n");
return -1;
}
printf("%s %s\n",argv[1],argv[2]);
SaveStudentMassage();
return 0;
}
代码解释:
1、flush(stdout):强制刷新
对于标准输出,需要输出的数据并不是直接输出到终端上,而是首先缓存到某个地方,当遇到行刷新标志或者该缓存已满的情况下,才会把缓存的数据显示到终端设备上。 ANSI C中定义换行符'n'可以认为是行刷新标志。 所以,printf函数没有带'n'是不会自动刷新输出流,直至缓存被填满。flush(stdout)的作用就是强制刷新,将缓冲区里的内容送到屏幕上。
2、int main(int argc,char * argv[])
argc是命令行总的参数个数
argv[]是argc个参数,其中第0个参数是程序的全名。argc和argv是你通过命令行窗口传给程序的。
当你需要程序带参数地启动的时候,就用int main(int argc, char *argv[])