基于VS2019 C++的跨平台(Linux)开发(1.2.2)——设备管理及文件IO

接上一篇文章,我们来回顾作业以及学习其他的一些系统调用等等

Linux——设备管理及文件IO(一)

一、回顾作业

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-tools​3、远程登录工具(远程登录工具包括:网络启动、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; 

二、其他系统调用 

9lseek系统调用 

作用:文件随机访问(光标定位)——通过文件标识符分别在文件开头位置、当前位置、结束位置进行偏移,和标准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);效果如下(将中文拆成了两半)

有时覆盖中文 出现乱码

注意点:从头往后写一定是正数,反之是负数

10fcntl系统调用 

文件锁定义:当有多个进程同时对某一文件进行操作时,就有可能发生数据的不同步,从而引起错误,该文件的最后状态取决于写该文件的最后一个程序。

作用: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;
}

11chmod和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)

原创不易,转载请注明出处

猜你喜欢

转载自blog.csdn.net/hml111666/article/details/123367886
今日推荐