接上一篇文章,我们来回顾作业以及学习其他的一些系统调用等等
一、回顾作业
1、知识点
1、文件IO分类
①纯文本文件:不能进行任何修饰,且只有文字的文件;如.cpp文件、.h文件、 txt文本文件
②二进制文件: 除纯文本文件以外的文件,一般指包含ASCII及扩展ASCII字符中编写的数据或程序指令的文件,如word、ppt、音视频、图片2、读取文件的存储方式
纯文本文件通过char数组保存;二进制文件通过int数组保存。
3、int数组和char数组使用sizeof和strlen的情况:
- int数组保存二进制文件数据使用sizeof,因为int数组没有'\0'结束符,不能用strlen(要求以'\0'结束),避免造成的文件乱码;
- char数组保存纯文本文件数据使用sizeof可能会多出\00等字符(当定义的数组的长度大于数组实际长度),使用strlen无问题。
strlen函数补充:
strlen函数求的是字符串的实际长度,是从开始到遇到第一个'\0'来求长度,如果你只定义没有给它赋初值,这个结果是不定的,它会从aa首地址一直找下去,直到遇到'\0'停止。
4、scanf函数存单个字符比较好,但是存很长很长的字符就要用cin函数
读取一行——cin.get 和cin.getline的比较:
cin.get
cin.getline
直接使用cin >> buf;
(1)由结果得,get读取一行,遇到换行符时结束读取,但不对换行符进行处理,换行符仍然残留在输入缓冲区。getline读取一行,默认遇到’\n’时停止(cin.getline(array,20,'\n');),并且将’\n’直接从输入缓冲区中删除掉,不会影响下面的输入处理。
(2)cin.get(str,size);读取一行时,只能将字符串读入C风格的字符串中,即char*,但是C++的getline函数可以将字符串读入C++风格的字符串中,即string类型。鉴于getline较cin.get()的这两种优点,建议使用getline进行行的读取。
(3)getline要回车换行后输入over才会结束;get不管输不输over,只要敲回车就结束了;如果直接使用cin >> buf;可以换行一直输入,但不会处理空格,换行符,直到输入over敲回车结束
参考链接:C++中cin的详细用法
5、ubuntu中播放视频要安装插件:在“系统设置”的“软件更新”中使用国内下载源 阿里云(福建地区推荐,比较快)、 清华 等(使用校园网下载可能会中断)
6、知识拓展(了解)
- ubuntu系统的的root文件夹如果有房子图标则为登录root用户登录,登录的是谁,home就显示谁的文件夹(如下图)
- 公司服务器都会要求稳定、安全,代码漏洞不会那么多,window系统下的 Window server也可以做服务器(linux是开源操作系统,其他系统都是基于linux进行更改,比如MAC、安卓、小红帽、麒麟、乌班图等等)
- 传输文件:1、共享目录2、vmware-tools3、远程登录工具(远程登录工具包括:网络启动、telnet、putty、secureCRT、winsCP等)
- 开源操作系统:源代码对外开放的系统,任何人都可以对其操作系统进行访问;访问后遇到的问题,任何人都可以对其讨论和解决,解决后官方将对其进行系统更新。
- 远程登录服务器:由于服务器集中在一个密闭的空间,避免高温影响服务器运行,需要进行降温(3度),因此人们不可能长时间进行线下操作解决服务器的问题,为了解决这个问题就需要对其进行远程操作;服务器程序运行不可见,只能通过系统指令进行操作;服务器大多远离办公区域
2、代码
第一题比较简单,直接利用封装好的函数实现视频拷贝
第二题核心代码如下
//法一
int read_fd = 0;
char buf[110] = { 0 };
std::fstream fs("/root/projects/demo2.txt", ios::app);
while(true)
{
cout << "please input :";
cin >> buf;
fs << buf << "\n";
cout << "continue? (input 'over' exit, others continue): ";
if (strcmp(buf,"over") == 0)
break;
cout << endl;
}
fs.close();
//法二(推荐)
int writefd = 0;
int res1 = 0;
char buf[110] = { 0 };
writefd = open("/root/projects/demo3.txt", O_CREAT | O_WRONLY | O_TRUNC, 0777);
if (writefd < 0)//打开文件失败,返回-1
{
perror("open file error");
}
else
{
cout << "please input (input 'over' to exit):";
while (true)
{
cin.getline(buf, 110);
if (strcmp(buf, "over") == 0)
{
close(writefd);
break;
}
else {
write(writefd, buf, strlen(buf));
bzero(buf, sizeof(buf));
}
}
}
//close(writefd);
return 0;
二、其他系统调用
9、lseek系统调用
作用:文件随机访问(光标定位)——通过文件标识符分别在文件开头位置、当前位置、结束位置进行偏移,和标准I/O库的fseek函数类似,可以移动当前读写位置
头文件:
#include <sys/types.h> #include <unistd.h>
函数原型:off_t lseek(int fd, off_t offset, int base);
参数:
- fd:需设置的文件标识符
- offset:偏移量(为负表示从后往前偏移)
- base:搜索的起始位置(base 的几个值如下表)
返回值:返回新的文件偏移值
base |
文件位置 |
SEEK_SET |
从文件开始处计算偏移 |
SEEK_CUR |
从当前光标位置计算偏移 |
SEEK_END |
从文件的结束处计算偏移 |
示例代码
int writefd = 0;
int res1 = 0;
char buf[50] = { "zhuo"};//中文不行
umask(0);
writefd = open("/root/projects/1.txt", O_CREAT | O_WRONLY, 0777);
lseek(writefd,5,SEEK_CUR);
res1 = write(writefd,buf,strlen(buf));
close(writefd);
说明:在写入数据到文本文件中时,如果光标位置后面数据,会进行数据覆盖;如果覆盖的是中文(utf-8中,中文占3个字节),可能会出现半个中文覆盖,半个中文没有覆盖的情况,\n(换行符)也算一个字节,也会被覆盖。
1、 lseek(writefd,5,SEEK_CUR);数组buf改为zhuo,效果如下
2、 lseek(writefd,10,SEEK_SET);数组buf改为c++,效果如下(覆盖了hello和换行符)
3、 lseek(writefd,12,SEEK_END);数组buf改为java,效果如下(偏移了12才写java)
4、 lseek(writefd,-28,SEEK_END);效果如下(将中文拆成了两半)
有时覆盖中文 出现乱码
注意点:从头往后写一定是正数,反之是负数
10、fcntl系统调用
文件锁定义:当有多个进程同时对某一文件进行操作时,就有可能发生数据的不同步,从而引起错误,该文件的最后状态取决于写该文件的最后一个程序。
作用:Linux中通过fcntl函数来实现对文件某一区域进行文件记录锁的控制。
头文件:
#include <unistd.h> #include <fcntl.h>
函数原型:
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);参数:
- fd:文件描述符;
- cmd:功能符号;(F_SETLK用来设置或释放锁;F_GETLK用来获得锁信息;)
- lock:存储锁信息的结构体指针;
返回值:调用成功返回0,失败返回-1
补充——锁信息结构体:struct flock { short l_type; /* 锁的类型 */ short l_whence; /* 偏移量的起始位置: */ off_t l_start; /* 从l_whence的偏移量 */ off_t l_len; /* 从l_start开始的字节数 */ pid_t l_pid; /* 锁所属进程ID(一般不用) */ } l_type有F_RDLCK读锁、F_WRLCK写锁及F_UNLCK空锁。 l_whence有SEEK_SET、SEEK_CUR和SEEK_END。 l_len为0时表示从起点开始直至最大可能位置为止。
示例代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int fd;
struct flock lock;
if((fd = open("demo1",O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1)
{
printf("打开文件失败\n");
return -1;
}
memset(&lock,0,sizeof(struct flock));
lock.l_start = SEEK_SET;
lock.l_whence = 0;
lock.l_len = 0;
if(fcntl(fd,F_GETLK,&lock) == 0)
{
if(lock.l_type != F_UNLCK)
{
printf("不能设置锁\n");
}
else
{
lock.l_type = F_WRLCK;
if(fcntl(fd,F_SETLK,&lock) == 0)
printf("设置写锁成功!\n");
else
printf("设置写锁失败!\n");
getchar();
//置为空锁
lock.l_type = F_UNLCK;
fcntl(fd,F_SETLK,&lock);
}
}
close(fd);
return 0;
}
11、chmod和fchmod系统调用
作用:用来改变给定路径名pathname的文件的权限位,一般在open系统调用时就已经完成了权限修改
函数原型:
int chmod (char *pathname, mode_t mode);
int fchmod (int fd, mode_t mode);
参数:
- pathname:文件路径名;
- mode:权限位
返回值:调用成功返回0,失败返回-1
12、chown和fchown系统调用
作用:用来改变文件所有者的识别号(owner id)或者它的用户组识别号(group ID)
函数原型:
int chown (char *pathname, uid_t owner,gid_t group);
int fchown (int fd, uid_t owner,gid_t group);
参数:
- pathname:文件路径名;
- mode:权限位
返回值:调用成功返回0,失败返回-1
13、mkdir系统调用
作用:用来创建一个称为pathname的新目录,它的权限位设置为mode
函数原型:
int mkdir(char *pathname,mode_t mode);
参数:
- pathname:文件路径名; 【fd:文件描述符】
- owner:所有者识别号
- group:用户组识别号
返回值:调用成功返回0,失败返回-1
14、rmdir系统调用
作用:删除一个空目录(需要先删除文件夹内的内容)
函数原型:int rmdir(char *pathname);
参数:
- pathname:文件路径名;
返回值:
调用成功返回0,失败返回-1
目录访问
- //cd ./当前目录
- //cd ../ 上一级目录
- // cd /根目录
- 子文件包括子文件夹以及隐藏的.跟..等,.和..是linux系统中预留的,所以可以通过.跟..进行文件夹跳转
15、opendir系统调用
作用:打开一个目录
函数原型:DIR* opendir(char *pathname);
参数:
- pathname:文件路径名;
返回值:
打开成功,返回一个目录指针;打开失败,则返回0
16、readdir系统调用
作用:访问指定目录中下一个连接的细节
函数原型:struct dirent* readdir ( DIR *dirptr);
参数:
- dirptr:目录指针
返回值:
返回一个指向dirent结构的指针,它包含指定目录中下一个连接的细节;没有更多连接时,返回NULL补充——目录信息结构体
struct dirent { ino_t d_ino; /* 目录i结点 索引节点号*/ off_t d_off; /* 在目录文件中的偏移*/ unsigned short d_reclen; /* 文件名长*/ unsigned char d_type; /*文件类型*/ char d_name[NAME_MAX+1]; /* 文件名, d_name[256]最长255字符*/ };
readdir返回指定文件夹中的数据,可以结合while 循环来进行文件夹下的所有文件的遍历:调用opendir打开某个目录之后,第一次调用readdir函数,则返回的是该目录下第一个文件的信息,第二次调用readdir函数返回该目录下第二个文件的信息,依此类推。如果该目录下已经没有文件信息可供读取,则返回NULL。
17、closedir系统调用
作用:关闭一个已经打开的目录
函数原型:int closedir (DIR *dirptr);
参数:
- dirptr:目录指针
返回值:
调用成功返回0,失败返回-1
示例代码
DIR* dir = NULL;
struct dirent* pdir = NULL;
if ((dir = opendir("/root/projects")) == NULL)//文件路径查看
{
perror("open file error");//perror可以查看具体错误
}
else {
while ((pdir = readdir(dir))!=NULL)//访问路径内的文件和目录
{
cout << "子文件名 " << pdir->d_name << endl;
}
}
return 0;
注:目录信息结构体不能在ubuntu中通过man来查看,它只能查看函数
基于VS2019 C++的跨平台(Linux)开发(1.2.2)
原创不易,转载请注明出处