2023-07-29:华清远见嵌入式2017年线下班:文件IO笔记

news2024/11/26 0:25:09

这里写目录标题

  • 华清远见嵌入式2017年线下班:文件IO笔记
    • 文件权限
    • 文件IO
      • 文件创建和打开操作
      • 文件关闭操作
      • 出错处理
      • 创建设备文件 || create || 老师自己忘了
      • 文件读操作
      • 练习:计算文件的大小?
      • 文件写操作
      • 练习:打开file1和file2,将file1中的内容拷贝到file2,实现文件拷贝功能
      • 文件定位操作
      • 练习:通过lseek计算文件的大小
      • 空洞与非空洞文件 (Linux)
      • 作业:打开file1,file2,file3 ,将file1前一半内容拷贝到file2,后一半内容拷贝file3```cpp
    • 标准IO
      • 文件读操作fopen
      • 读写流
      • 练习: 循环的从标准输入中获取字符(如果是数字则显示,其他的就不显示)
      • 练习:要求输入字符,将大写字母转换成小写,小写字母转换成大写。
      • 行IO
      • 练习:获取以个文件的行数。
      • 检查文件出错函数
      • 直接IO
      • 流的格式化输入输出
      • 流的定位
      • 获取时间
      • 文件信息
      • 硬链接和软连接
      • 获取用户相关信息
      • 获取用户分组
      • 目录操作函数
      • 静态库特点
      • 共享库的特点
      • 如何找到共享库

华清远见嵌入式2017年线下班:文件IO笔记

文件权限

在这里插入图片描述

(一)第一个字段表示文件类型 和 文件权限。
第1个字母表示文件类型:d表示目录类型。其他的linux 文件类型以下七种:
在这里插入图片描述(二)其他6个字母表示分别表示属主权限,属组权限,其他用户权限。
权限构成


文件权限由三个部分构成,分别为

文件所有者 User
同组用户 Group
其他用户 Other

每个部分可以用一个数字或三个字母表示:

读取的权限等于4,用r表示
写入的权限等于2,用w表示
执行的权限等于1,用x表示

数字解释
rwx 属性:4+2+1 = 7;
rw- 属性:4+2 = 6;
r-x 属性:4+1 = 7。

以755为例:
1-3 位 7:等于4+2+1,rwx,所有者具有读取、写入、执行权限;
4-6 位 5:等于4+1+0,r-x,同组用户具有读取、执行权限但没有写入权限;
7-9 位 5:等于4+1+0,r-x,其他用户具有读取、执行权限但没有写入权限。

444 r–r–r–
600 drw-------
644 drw-r–r–
666 drw-rw-rw-
700 drwx------
744 drwxr–r–
755 drwxr-xr-x
777 drwxrwxrwx

文件IO

类Linux系统下使用

文件创建和打开操作

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 : 需要打开文件的文件名,文件名长度不能超过255。 flags : 打开方式

O_RDONLY:只读方式打开文件。  
O_WRONLY:可写方式打开文件。 
O_RDWR:读写方式打开文件。 
O_CREAT:如果该文件不存在,就创建一个新的文件,并用第三的参数为其设置权限(读写执行权限)。 
O_EXCL:如果使用
O_CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在。 
O_TRUNC:如文件已经存在,那么打开文件时先删除文件中原有数据。
O_APPEND:以添加方式打开文件,所以对文件的写操作都在文件的末尾进行。//write 文件开始位置开始写

文件关闭操作

#include <unistd.h>
int close(int fildes);
函数参数:
fildes : 需要关闭文件的文件描述符
返回值:
	成功 0 
	失败 -1

例1:以所有者只写方式(参数O_WRONLY)打开文件(mode=64),如果文件不存在则创建(参数O_CREAT),如果文件存在则清空(参数O_TRUNC)。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>


/*
以所有者只写方式(参数O_WRONLY)打开文件(mode=64),
如果文件不存在则创建(参数O_CREAT),
如果文件存在则截短(参数O_TRUNC)
*/

int main(int argc, const char *argv[])
{
	int fd;
	
	// 不指定umask生成的test.txt文件的权限是0664,指定了就是0666
	umask(0); 
	
	// 在当前目录创建"test.txt"
	// 0666 = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
	// fd = open("test.txt", 
	//           O_WRONLY | O_CREAT | O_TRUNC , 
	//           S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,0666);
	if(-1 == fd)
	{
		perror("open failed");// 后面会自动接perror对应的错误信息
	}
	close(fd);//1024
	
	return 0;
}

在终端中执行,使用命令 ./open

如果存在text.txt文件,perror则会报错,自动提示错误信息
在这里插入图片描述
文件权限还可以使用宏进行表示
在这里插入图片描述

出错处理

#include <string.h>
char * strerror(int errnum);
全局错误码errno 是记录系统的最后一次错误代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h> //一定要加这个头文件
/*
以所有者只写方式(参数O_WRONLY)打开文件(mode=64),
如果文件不存在则创建(参数O_CREAT),
如果文件存在则截短(参数O_TRUNC)
*/
int main(int argc, const char *argv[])
{
	int fd;
	
	// 不指定umask生成的test.txt文件的权限是0664,指定了就是0666
	umask(0); 
	
	// 在当前目录创建"test.txt"
	fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,0666);
	if(-1 == fd)
	{
		print("%s\n", strerror(errno));// errno是记录系统的最后一次错误代码
	}
	close(fd);//1024
	
	return 0;
}

在这里插入图片描述

创建设备文件 || create || 老师自己忘了

cat /proc/devices 查看当前系统支持的驱动
在这里插入图片描述
主设备号
usb 字符设备
180 设备号

int creat(const char *pathname, mode_t mode);
等价于open(pathname,
O_CREAT|O_WRONLY|O_TRUNC, mode)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, const char *argv[])
{
	int fd;
	fd = creat("test.txt", 0666); // open("test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
	if(-1 == fd)
	{
		perror("creat");
	}
	close(fd);//1024
	return 0;
}

文件读操作

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

函数功能:
	从一个已经打开的文件中读取内容

函数参数:
	fd : 文件描述符
	buf : 用来存放读到的内容的缓冲区首地址
	count :读取的字节数

返回值:
	成功: 返回实际读取的字节数(0 读到文件末尾)
	失败: -1 并设置errno
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd;
	char buf[1024] = "\0"; // 可以人为指定,不能超过1024字节
	int count;
	
	fd = open("test.txt", O_RDONLY | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	if(-1 == fd)
	{
		perror("open failed");
	}

    // 每次读取5个字节
	while((count = read(fd, buf, 5)) > 0) // 不能 >=
	{
		if(-1 == count)
		{
			perror("read failed");
			return -1;
		}
		printf("count = %d : %s\n", count, buf); //count = 5
	}

	close(fd);//1024

	return 0;
}

练习:计算文件的大小?

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd;
	char buf[1024] = "\0";
	int count = 0 , sum  = 0;
	
	fd = open("test.txt", O_RDONLY | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	if(-1 == fd)
	{
		perror("open failed");
	}


	while((count = read(fd, buf, 5)) > 0)
	{
		if(-1 == count)
		{
			perror("read failed");
			return -1;
		}
		sum = sum + count;
	}

	printf("The size of file is %d\n", sum);
	close(fd);//1024

	return 0;
}

文件写操作

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

函数功能:
	向已经打开的文件中写内容
函数参数:
	fd : 文件描述符
	buf :  写缓冲缓冲区首地址
	count : 指定写入的字节数
返回值:
	成功:实际写到文件的字节数
	失败:-1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd;
	char buf[1024] = "\0";
	char writebuf[1024] = "xxxxx";
	int count;
	//	fd = open("test.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	// 没有O_APPEND,直接覆盖
	fd = open("test.txt", O_RDWR | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); 
	if(-1 == fd)
	{
		perror("open failed");
	}

	count = read(fd, buf, 1);
	if(-1 == count)
	{
		perror("read failed");
		return -1;
	}
	printf("count = %d : %s\n", count, buf);
	
	count = write(fd, writebuf, strlen(writebuf));
	if(-1 == count)
	{
		perror("write failed");
		return -1;
	}
	printf("count = %d\n", count);

// 这里读了一个字符,所以偏移了1
	count = read(fd, buf, 1); 
	if(-1 == count)
	{
		perror("read failed");
		return -1;
	}
	printf("count = %d : %s\n", count, buf);
	close(fd);//1024

	return 0;
}

text.txt里原来的内容是 “abcdefghijk”
在这里插入图片描述输出:文件初始read了一个字符,位移在第一位,往后覆盖 xxxxx

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd;
	char buf[1024] = "\0";
	char writebuf[1024] = "xxxxx";
	int count;

	// 有O_APPEND
	fd = open("test.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	if(-1 == fd)
	{
		perror("open failed");
	}

	count = read(fd, buf, 1);
	if(-1 == count)
	{
		perror("read failed");
		return -1;
	}
	printf("count = %d : %s\n", count, buf);
	
	count = write(fd, writebuf, strlen(writebuf));
	if(-1 == count)
	{
		perror("write failed");
		return -1;
	}
	printf("count = %d\n", count);

	count = read(fd, buf, 1);
	if(-1 == count)
	{
		perror("read failed");
		return -1;
	}
	printf("count = %d : %s\n", count, buf);
	close(fd);//1024

	return 0;
}

在这里插入图片描述输出:在下一行追加 xxxxx

练习:打开file1和file2,将file1中的内容拷贝到file2,实现文件拷贝功能

diff -s file1 file2 (比较两个文件是否一致)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd1, fd2;
	char buf[1024] = "\0";
	int count;
	
	if(argc < 3)
	{
		printf("command error <source file> <dest file>!\n");
		return -1;
	}

	// 从命令行参数获得文件名
	fd1 = open(argv[1], O_RDONLY);
	if(-1 == fd1)
	{
		perror("open file1 failed");
		return -1;
	}
	
	fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
	if(-1 == fd2)
	{
		perror("open file2 failed");
		return -1;
	}

	while((count = read(fd1, buf, sizeof(buf))) > 0)
	{
		write(fd2, buf, count);
	}

	close(fd1);//1024
	close(fd2);//1024

	return 0;
}

文件定位操作

#include <sys/types.h>

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

函数功能:文件定位
函数参数:
	fd:文件描述符
	offset:相对于偏移量
	偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)
	whence: 基准点
	
SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小。
SEEK_CUR:当前位置为文件指针的位置,新位置为当前位置加上偏移量。
SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量的大小。

返回值:
	失败 :-1
	成功:当前文件的偏移量(当前读写位置相对文件开始位置的字节数)
	
通过lseek计算文件的大小
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd;
	char buf[1024] = "\0";
	char writebuf[1024] = "xxxxx";
	int count;
	int offset;
	fd = open("test.txt", O_RDWR | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	if(-1 == fd)
	{
		perror("open failed");
	}
	
	count = write(fd, writebuf, strlen(writebuf));
	if(-1 == count)
	{
		perror("write failed");
		return -1;
	}
	printf("count = %d\n", count);

	//offset = lseek(fd, -6, SEEK_CUR);
	offset = lseek(fd, -5, SEEK_CUR);
	if(-1 == offset)
	{
		perror("lseek");
		return -1;
	}

	count = read(fd, buf, 5);
	if(-1 == count)
	{
		perror("read failed");
		return -1;
	}
	printf("count = %d : %s\n", count, buf);
	close(fd);//1024

	return 0;
}

新建文件,写入“xxxxx”,然后读取出来。
在这里插入图片描述
如果向前偏移量越界,时候会直接报错
在这里插入图片描述

练习:通过lseek计算文件的大小

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd;
	char buf[1024] = "\0";
	char writebuf[1024] = "xxxxx";
	int count;
	int offset;
	
	fd = open("test.txt", O_RDWR | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	if(-1 == fd)
	{
		perror("open failed");
	}
	
	//SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量0的大小
	offset = lseek(fd, 0, SEEK_END);
	if(-1 == offset)
	{
		perror("lseek");
		return -1;
	}

	printf("sizeof file is  %d \n", offset);
	close(fd);//1024

	return 0;
}

空洞与非空洞文件 (Linux)

空洞文件和真实文件的区别在于磁盘的使用情况
du -sh 查看空洞文件和真实文件的区别

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd;
	char buf[32] = "hello, world";
	int offset;
	
	fd = open("hole.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
  if(fd < 0)
  {
  	printf("%s\n",sterror(errno));
  	return -1;
  }

  write(fd, buf, strlen(buf));
	if((offset = lseek(fd, 168898, SEEK_CUR)) < 0)
	{
		perror("lseek");
		return -1;
	}

	write(fd, buf, strlen(buf));
	 
	close(fd);//1024

	return 0;
}

在这里插入图片描述在这里插入图片描述
前后都有hello world.中间全是空洞

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd;
	char buf[32] = "hello, world";
	int offset;
	
	fd = open("hole.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
  if(fd < 0)
  {
  	printf("%s\n",sterror(errno));
  	return -1;
  }

  write(fd, buf, strlen(buf));
	/*
	if((offset = lseek(fd, 168898, SEEK_CUR)) < 0)
	{
		perror("lseek");
		return -1;
	}
*/
//真实地往磁盘里写内容
	for(i = 0; i < 168898; i++)
	{
		write(fd, "x", 1);
	}
	
	write(fd, buf, strlen(buf));
	 
	close(fd);//1024

	return 0;
}

在这里插入图片描述空洞和非空洞文件都是165K
在这里插入图片描述但是可以通过查看磁盘使用情况区别两个文件的内存大小
在这里插入图片描述

作业:打开file1,file2,file3 ,将file1前一半内容拷贝到file2,后一半内容拷贝file3```cpp

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd1, fd2, fd3, count, nread, size;
	int buf[1024] = "\0";
	
	if(argc < 4)
	{
		printf("argc < 4");
		return -1;
	}
	
	fd1 = open(argv[1], O_RDONLY);
  if(fd1 < 0)
  {
  	printf("%s\n",sterror(errno));
  	return -1;
  }

	fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
  if(fd2 < 0)
  {
  	printf("%s\n",sterror(errno));
  	return -1;
  }
	fd3 = open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0666);
  if(fd3 < 0)
  {
  	printf("%s\n",sterror(errno));
  	return -1;
  }
	size = lseek(fd1, 0, SEEK_END);
	lseek(fd1, 0, SEEK_SET)

	while((nread = read(fd1, buf, 1)) > 0)
	{
		count++;
		if(count <= (size/2))
			write(fd2, buf, nread);
		else if (count > (size/2))
		  write(fd3, buf, nread);
	}	 
	close(fd1);//1024
	close(fd2);//1024
	close(fd3);//1024
	return 0;
}

标准IO

只要装了C库,就能使用标准IO

open 返回 fd
fopen 返回指向FILE结构的指针

1)理解什么是流?
输入流入和流出的对象就是流

2)如何描述一个流
内存中开辟一个区域,用来存放流的有关信息,这些信息是保存在一个结构体类型的变量中,该结构体类型是由系统定义的,取名为FILE.

3)FILE 指针
fopen 返回指向FILE结构的指针

流的分类:
文本流和二进制流
(Linux不区分文本和二进制流, windows)

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int i = 0;

	for(i = 0;i < 379;i++) //每次向缓冲区写3个字符
	{
			if (i >= 100)
				fprintf(stdout,"%d",i);
			else if (i >= 10)
				fprintf(stdout,"0%d",i);
			else if (i >= 0)
				fprintf(stdout,"00%d",i);
		}
		while(1);
		return 0;
	}

目标是打印000-376,
实际上只输出前1024字节,
1024/3=341.3 个数,
即000-340.3,因此结尾的4个数是340|3
在这里插入图片描述

getchar(); /* why do we need this? 实际使用时才会申请空间*/

缓冲:
	缓冲区是通过malloc申请的空间
	申请的实际,是发生I/O操作的时候

当程序调用getchar时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中),当用户键入回车之后,getchar才开始从stdio流中每次读入一个字符。

getchar函数的返回值是用户输入的字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕.

总结一下:
	对于磁盘文件通常使用全缓冲区访问。
	当流涉及一个终端时(例如标准输入和标准输出),使用行缓冲区
	标准出错流stderr 通常是不带缓冲区的
#include <stdio.h>
/*1.測試標準輸入和標準輸出採用的是什麼類型的緩衝以及緩衝區的大小
 *2.普通文件採用的是什麼類型的緩衝以及緩衝區的大小
 *3.malloc的時間
 * */
int stream_attribute(FILE *fp)
{
	if(fp->_flags & _IO_UNBUFFERED) {
		printf("The IO type is unbuffered\n");
	} else if (fp->_flags & _IO_LINE_BUF) {
		printf("The IO type is line buf\n");
	} else {
		printf("The IO type is full buf\n");
	}
	printf("The IO buffer size = %d (bytes)\n", fp->_IO_buf_end - fp->_IO_buf_base);
	return 0;
}

int main()
{
	FILE *fp;
	// 尝试注释掉getchar();观察输出有什么不同
	getchar(); /* why do we need this? 实际使用时才会申请空间*/

	printf("stdin  ___________________________________\n");	
	stream_attribute(stdin);
	
	printf("stdout ___________________________________\n");
	stream_attribute(stdout);
	
	printf("stderr ___________________________________\n");
	stream_attribute(stderr);

	printf("normal file ___________________________________\n");//普通文件
	if ((fp = fopen("test.txt","w+")) == NULL) {
		perror("fail to fopen");
	}

	printf("before write:\n");
	stream_attribute(fp);
	fputc('a', fp); //putchar('a') == fputc('a', stdout)
	printf("after write:\n");
	stream_attribute(fp);

	return 0;
}

在这里插入图片描述

文件读操作fopen

#include <stdio.h>

FILE *fopen(const char *path, const char *mode);

FILE *fdopen(int fd, const char *mode);

FILE *freopen(const char *path, const char *mode, FILE *stream);

path : 路径名
mode : 打开方式
r
r+
w
w+
a
a+

返回值:
	成功返回 指向FILE的结构体指针(流指针)
	失败返回 NULL

./hello > file

FILE *freopen(const char *path, const char *mode, FILE *stream);
	作用:重定向输入输出流
	
const char *restrict pathname:
	重新定向的文件或者是路径
	
const char *restrict type:
	文件打开的方式
	
restrict fp
被改变的流

返回一个新的FILE指针
freopen("file1", "w+", stdout);

读写流

fgetc和getc基本一致,除了getc()可能是由宏实现的,getchar () == getc(stdin) 。

#include <stdio.h>

int getc(FILE *stream);

int fgetc(FILE *stream);

int getchar(void);

函数参数:
	stream : 流
从指定流中获取一个字符

函数返回值:
	成功 返回读到字符的ascII码
	失败 EOF
到文件末尾

getchar()等同于getc(stdin);

#include <stdio.h>

int putc(int c, FILE *stream);

int fputc(int c, FILE *stream);

int putchar(int c);

注意:三个函数在使用的时候要一一对应
	c : 输出的字符(acII码)
	stream : 指定的流

putchar(c)等价于putc(c,stdout)

练习: 循环的从标准输入中获取字符(如果是数字则显示,其他的就不显示)

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, const char *argv[])
{
	int c;
	while(1)
	{
		c = fgetc(stdin);
		if( ( c >= '0' ) && ( c <= '9') )
			fputc(c, stdout);
		else if('\n' == c)
			break;
	}
	return 0;
}

练习:要求输入字符,将大写字母转换成小写,小写字母转换成大写。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int c;
	while(1)
	{
		c = fgetc(stdin); //放到了缓冲区
		
		if((c >= 'a') && (c <= 'z'))
		{
			c = c - ('a' - 'A');
			fputc(c, stdout);
		}
		else if((c >= 'A') && (c <= 'Z'))
		{
			c = c + ('a' - 'A');
			fputc(c, stdout);
		}
		if('\n' == c)
			break;
	}
	return 0;
}

行IO

char * fgets(char *s, int size, FILE *stream);

char *gets(char *s);

char* s:用于存储从制定流的缓冲区中获取的数据的首地址
size:缓冲区的长度
stream:指定的流

fgets
(1) 必须指定缓存的长度n。
此函数一直读到下一个新行符为止,但是不超过n-1个字符,读入的字符被送入缓存。该缓存以null字符结尾。

(2) 如若该行,包括最后一个新行符的字符数超过n-1,则只返回一个不完整的行,而且缓存总是以null字符结尾。对fgets()的下一次调用会继续读该行。
缓存:buf[7]
在这里插入图片描述
(3) gets()与fgets()的另一个区别是,gets()并不将换行符存入缓存中,fges会将换行符存到存到缓冲区中

#include <stdio.h>

int main(int argc, const char *argv[])
{
	char buf[32];
	gets(buf);
//	fgets(buf, sizeof(buf), stdin);
	printf("%s", buf);
	return 0;
}

在这里插入图片描述

注意1:char *fgets(char *s ,int size,FILE *stream)的用法

fgets每次至多多size-1个字符,每次都把都到的字符存储到s字符串数组内,当读到文件末尾(EOF)或者是换行的时候它会结束。换行符(‘/n’),会被存储到字符数组内部,结束时会在字符数组最后一位补一个空位(’/0’)。

如果文件中的该行,不足bufsize个字符,则读完该行就结束。如若该行(包括最后一个换行符)的字符数超过bufsize-1,则fgets只返回一个不完整的行,但是,缓冲区总是以NULL字符结尾,对fgets的下一次调用会继续读该行。

如果n大于一行的字符串长度,那么当读到字符串末尾的换行符时,fgets(..)会返回。并且在s的最后插入字符串结束标志'\0'。 而s缓冲区剩余的位置不会再填充。

注意2:char *gets(char *s,FILE *stream)

gets不推荐使用,该函数容易造成缓冲区的溢出,造成不良的后果。

二进制直接I/O。fread()和fwrite()函数支持这种类型的I/O。每次I/O操作读或写某种数量的对象,而每个对象具有指定的长度。这两个函数常用于从二进制文件中读或写一个结构。

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

练习:获取以个文件的行数。

#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	FILE *fp;
	char buf[1024] = "\0";
	int line = 0;
	//step 1: 打开流
	fp = fopen(argv[1], "r");
	if(NULL == fp)
	{
		perror("fopen");
		return -1;
	}
	
	//step 2: 获取行号
	while(fgets(buf, sizeof(buf), fp) != NULL)
	{
		if(buf[strlen(buf) - 1] == '\n')
			line++;
	}

	printf("The line of %s is %d\n", argv[1], line);
	return 0;
}

int puts(const char *s);

函数功能:
 向标准输出输出一行

int fputs(const char *s, FILE *stream);

 函数功能:
 	向指定的流里输出一行

函数fputs()将一个以null符终止的字符串写到指定的流,终止符null不写出。

== 注意,这并不一定是每次输出一行,因为它并不要求在null符之前一定是新行符。==

#include <stdio.h>

int main(int argc, const char *argv[])
{
 // 中间添加'\0'
	char buf[] = {'a', 'b', 'c','\0', 'd' , 'e', 'f', '\n', '\0'};
	fputs(buf, stdout);
	puts(buf);
	return 0;
}

在这里插入图片描述

puts()将一个以null符终止的字符串写到标准输出,终止符不写出。但是,puts()然后又将一个新行符写到标准输出。

#include <stdio.h>

int main(int argc, const char *argv[])
{
 // 中间添加'\0'
	char buf[] = {'a', 'b', 'c', 'd' , 'e', 'f', '\n', '\0'};
	//fputs(buf, stdout);
	puts(buf);
	return 0;
}

在这里插入图片描述 注意:
puts()然后又将一个新行符写到标准输出。fputs不加换行符。

检查文件出错函数

#include <stdio.h>

void clearerr(FILE *stream);

int feof(FILE *stream);

int ferror(FILE *stream);

函数描述
feof : 用于检测文件末尾标志,如果该标志被设置返回非0的值,如果没有被设置返回0

ferror :用于检测出错标志,如果该标志被设置返回非0的值,如果没有设置返回0

clearerr :用于清除这两个标志

用法:

 while (!feof(fp) && !ferror(stdin)) {
 	cTemp = fgetc(fp);
  } 

直接IO

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

函数参数:
	ptr: 缓冲区的首地址
	stream : 流
	nmemb :元素个数(人为指定的)
	size : 每个元素的大小(人为指定)

返回值:
	成功 实际读到元素的个数(凑不足一个元素就不算)
	失败 -1

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

函数参数:
	ptr : 缓冲区首地址
	size : 元素的daxiao
	nmemb :元素的个数
	stream : 流

返回值:
	成功 实际写入的元素的个数
	失败 -1
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, const char *argv[])
{
	FILE *fp;
	int data[10];
	int data1[10];
	int i;

	for(i = 0; i < 10; i++)
	{
		data[i] = i;
	}

	if((fp = fopen("test_file", "w+")) == NULL)
	{
		fprintf(stderr, "fopen failed : %s", strerror(errno));
		return -1;
	}

	fprintf(stdout, "[DEBUG] sizeof(int) = %d\n", sizeof(int));

	// fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
	// data为缓冲区首地址
	// fwrite把缓冲区的写入fp
	if(fwrite(data, sizeof(int), 3, fp) != 3)
	{
		perror("fwrite");
		return -1;
	}
	
	fseek(fp, 0, SEEK_SET);
	
	// 换数组data1
	// fread把fp的写入缓冲区data1
	if(fread(data1, 3, 2, fp) != 2)
	{
		perror("fread");
		return -1;
	}
	
	// 输出缓冲区
	for(i = 0; i < 3; i++)
	{
		printf("%d ", data1[i]);
	}

	fclose(fp);
	return 0;
}

在这里插入图片描述凑不够字节的时候

#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, const char *argv[])
{
	FILE *fp;
	char buf[20] = "\0";
	int nread;
	if((fp = fopen("test_file", "r")) == NULL)
	{
		fprintf(stderr, "fopen failed : %s", strerror(errno));
		return -1;
	}

// nread读取2个元素,每个元素3个字节,所以需要读取6个字节
	if((nread = fread(buf, 3, 2, fp)) == -1)
	{
		perror("fread");
		return -1;
	}

	printf("%s\n", buf);
	printf("nread = %d\n", nread);
	fclose(fp);
	return 0;
}

"test_file"里只有1 2 3 4 \0, 5个字节
nread读取2个元素,每个元素3个字节,所以需要读取6个字节,
但是因为"test_file"只有5个字节,所以只能成功读取1个元素,nread==1,凑不够就不算。

在这里插入图片描述

流的格式化输入输出

int printf(const char *format, …); //输出到stdout

int fprintf(FILE *stream, const char *format, …); //输出到stream

int sprintf(char *str, const char *format, …); // 输出到char *str

#include <stdio.h>

int main(int argc, const char *argv[])
{
	FILE *fp = NULL;
	int a = 10;
	char buf[32] = "hello world";
	fp = fopen("test", "w+");
	if(NULL == fp)
	{
		perror("fopen_2");
		return -1;
	}
	fprintf(fp, "%d %s\n",a, buf);
	printf("%s\n", buf);
	
	// 缓冲区被覆盖
	sprintf(buf, "hello farsight %d", a);
	printf("%s\n", buf);
	
	a = 11;
	fprintf(fp, "%d %s\n",a, buf); 
	fclose(fp);
	return 0;
}

在这里插入图片描述

#include <stdio.h>
int scanf(const char *format, …); //stdin

int fscanf(FILE *stream, const char *format, …);//stream

#include <stdio.h>

int main(int argc, const char* argv[])
{
	FILE* fp = NULL;
	int a = 10;
	char buff[32] = "\0";

	fp = fopen("test", "r+");

	if (NULL == fp)
	{
		perror("fopen");
		return -1;
	}

	fscanf(fp,"%s%d", buff, &a);
	printf("%s, %d\n", buff, a);
	fclose(fp);
	return 0;
}

在这里插入图片描述>

int sscanf(const char *str, const char format, …);//charstr

#include <stdio.h>

int main(int argc, const char* argv[])
{
	FILE* fp = NULL;
	int a, b;
	char buff[32] = "\0";
	char buf[32] = "1 2 hello";

	fp = fopen("test", "r+");

	if (NULL == fp)
	{
		perror("fopen_2");
		return -1;
	}

	sscanf(buf, "%d%d%s", &a, &b, buff);

	printf("%s, %d, %d\n", buff, a, b);
	fclose(fp);
	return 0;
}

在这里插入图片描述

流的定位

int fseek(FILE *stream, long offset, int whence);
off_t lseek(int fd, off_t offset, int whence);

参数说明
	stream : 打开的流
	offset : 相对于基准点偏移量
	whence : 基准点

返回值:                                              返回值:偏移量
	成功 返回0
	失败 返回-1

返回当前流的偏移量

long ftell(FILE *stream);

#include <stdio.h>

int main(int argc, const char *argv[])
{
	FILE *fp;
	int ret;
	long int size;
	fp = fopen(argv[1], "r+");
	if(NULL == fp)
	{
		perror("fopen");
		return -1;
	}
	ret = fseek(fp, 0, SEEK_END);
	if(-1 == ret)
	{
		perror("fseek");
	}
	size = ftell(fp);
	printf("sizeo file is %ld\n", size);

	return 0;
}

void rewind(FILE *stream);
rewind() 等价于 (void)fseek(stream, 0L, SEEK_SET)

实验三:

  1. 打开文件方式(a+)
  2. 接上一次的行号(计算行号)

获取时间

time

#include <time.h>

time_t time(time_t *t); time_t == long

函数功能:
	返回从1970-1-1 0:0:0到函数调用那一刻的秒数
	如果t非NULL,就将时间填入到t所指向的内存空间

返回值:
	成功 : 时间
	失败 :((time_t) -1) 

#include <time.h>

struct tm *localtime(const time_t *timep);

函数功能:
	将秒数转换成具体的时间

函数参数:
	timep : 存秒数的地址

返回值:
#include <stdio.h>
#include <time.h>

int main(int argc, const char *argv[])
{
	time_t mytime;
	struct tm *p;
	mytime = time(NULL);

	p = localtime(&mytime);
	printf("%d-%d-%d %d:%d:%d\n", p->tm_year+1900, p->tm_mon+1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
	return 0;
}

文件信息

获取文件属性:

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

int stat(const char *path, struct stat *buf);

int fstat(int fd, struct stat *buf);

int lstat(const char *path, struct stat *buf);

函数参数:

struct stat {
               dev_t     st_dev;     /* ID of device containing file */
               ino_t     st_ino;     /* inode number */
               mode_t    st_mode;    /* protection */
               nlink_t   st_nlink;   /* number of hard links */
               uid_t     st_uid;     /* user ID of owner */
               gid_t     st_gid;     /* group ID of owner */
               dev_t     st_rdev;    /* device ID (if special file) */
               off_t     st_size;    /* total size, in bytes */
               blksize_t st_blksize; /* blocksize for file system I/O */
               blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
               time_t    st_atime;   /* time of last access */
               time_t    st_mtime;   /* time of last modification */
               time_t    st_ctime;   /* time of last status change */ };
三个函数的返回:若成功则为0,若出错则为-1,并且设置errno.

给定一个pathname的情况下:
	stat函数返回一个与此命名文件有关的信息结构
	fstat函数获得已在描述符filedes上打开的文件的有关信息
	lstat函数类似于stat,但是当命名的文件是一个符号连接时,lstat返回该符号连接的有关信息,而不是由该符号连接引用的文件的信息
	stat与之相反,返回的是链接文件引用的文件的信息
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	struct stat buf;
	stat(argv[1], &buf);	
	printf("size of %s is %d\n", argv[1], buf.st_size);
	return 0;
}

在这里插入图片描述st_mode

首先S_IFMT是一个掩码,它的值是017000(注意这里用的是八进制), 可以用来过滤出前四位表示的文件类型。

其后的连续七个分别对应套接口文件、符号链接文件、普通文件、块设备、目录、字符设备、管道,它们分别对应一个不同的值。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	struct stat buf;

	lstat(argv[1], &buf);	
#if 0
	if(S_ISREG(buf.st_mode))
		printf("regular file\n");
	else if(S_ISDIR(buf.st_mode))
		printf("directory\n");
	else if(S_ISCHR(buf.st_mode))
		printf("character device\n");
	else if(S_ISBLK(buf.st_mode))
		printf("block device\n");
	else if(S_ISFIFO(buf.st_mode))
		printf("FIFO\n");
	else if(S_ISLNK(buf.st_mode))
		printf("symbolic link\n");
	else if(S_ISSOCK(buf.st_mode))
		printf("socket\n");
#else
	switch(S_IFMT & buf.st_mode)
	{
		case S_IFSOCK:
			printf("socket\n");break;
		case S_IFLNK:
			printf("symbolic link\n");break;
		case S_IFREG:
			printf("regular file\n");break;
		case S_IFBLK:
			printf("block device\n");break;
		case S_IFDIR:
			printf("directory\n");break;
		case S_IFCHR:
			printf("character device\n");break;
		case S_IFIFO:
			printf("FIFO\n");break;
		default:
			printf("error\n");
	}

#endif
	return 0;
}

在这里插入图片描述

硬链接和软连接

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	struct stat buf;
	stat(argv[1], &buf);	
	printf("number of hand link is %d\n", buf.st_nlink);
	return 0;
}

在这里插入图片描述

获取用户相关信息

#include <sys/types.h>

#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
uid : 用户ID

struct passwd {
               char   *pw_name;       /* username */
               char   *pw_passwd;     /* user password */
               uid_t   pw_uid;        /* user ID */
               gid_t   pw_gid;        /* group ID */
               char   *pw_gecos;      /* user information */
               char   *pw_dir;        /* home directory */
               char   *pw_shell;      /* shell program */
};
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>

int main(int argc, const char *argv[])
{
	struct stat buf;
	struct passwd *p;
	stat(argv[1], &buf);	
	p = getpwuid(buf.st_uid);
	printf("file owner is %s\n", p->pw_name);
	return 0;
}

在这里插入图片描述

获取用户分组

#include <sys/types.h>

#include <grp.h>

struct group *getgrgid(gid_t gid);
gid :用户组ID

struct group {
               char   *gr_name;       /* group name */
               char   *gr_passwd;     /* group password */
               gid_t   gr_gid;        /* group ID */
               char  **gr_mem;        /* group members */
};
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>

int main(int argc, const char *argv[])
{
	struct stat buf;
	struct group *p;
	stat(argv[1], &buf);	
	p = getgrgid(buf.st_gid);
	printf("file group is %s\n", p->gr_name);
	return 0;
}

在这里插入图片描述

目录操作函数

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>

int main(int argc, const char *argv[])
{
	DIR *dir;
	struct dirent *p;
	//step 1:打开目录
	dir = opendir(argv[1]);	
	if(NULL == dir)
	{
		perror("opendir");
		return -1;
	}
	//step 2:读目录
	while((p = readdir(dir)) != NULL)
	{
		if(!strncmp(".", p->d_name, 1))
			continue;
		printf("%s\t", p->d_name);
	}
	printf("\n");
	//step 3:关闭目录
	closedir(dir);
	return 0;
}

Linux的库文件保存在 /lib /usr/lib文件夹下
Linux和window下库文件的格式不兼容

静态库特点

编译(链接)时把静态库中相关代码复制到可执行文件中,直接加载静态库中对应的代码 (不是全部,是部分)。

程序中已包含代码,运行时不再需要静态库。

静态库升级后,程序需要重新编译链接。

编写库源码hello.c

#include <stdio.h>
void hello(void) {
	printf(“hello world\n”);
	return;
}

编译生成目标文件

gcc -c hello.c -Wall

创建静态库 hello

ar crs libhello.a hello.o

静态库名称:libhello.a

名称都是有规范的:libXXXX.a

根据后面的执行文件hello.o生成静态库

查看库中符号信息

nm libhello.a

在这里插入图片描述
链接静态库

编写应用程序test.c

#include <stdio.h>
void hello(void);

int main() {
	hello();
return 0;
}

编译test.c 并链接静态库libhello.a

gcc -o test test.c -L. -lhello

在这里插入图片描述因为静态库里的代码已经加载到了程序里,所以删除静态库,不影响程序执行
在这里插入图片描述

共享库的特点

编译(链接)时仅记录用到哪个共享库中的哪个符号,不复制共享库中相关代码。

程序不包含库中代码,尺寸小。

程序运行时需要加载库。

库升级方便,无需重新编译程序。

编写库源码hello.c bye.c

#include <stdio.h>

void hello(void) {
	printf(“hello world\n”);
	return;
}
#include <stdio.h>

void hello(void) {
	printf(“Bye\n”);
	return;
}

编译生成目标文件

gcc -c -fPIC hello.c bye.c -Wall

使用相对寻址,可以加载到不同位置

创建共享库 common

gcc -shared -o libcommon.so.1 hello.o bye.o

libcommon.so.1:libcommon.so.X的X代表库的版本,libcommon.so.2,libcommon.so.3…

在这里插入图片描述

为共享库文件创建链接文件

ln -s libcommon.so.1 libcommon.so

符号链接文件命名规则

lib<库名>.so
在这里插入图片描述链接共享库
编写应用程序test.c
在这里插入图片描述

#include <stdio.h>
#include “common.h”

int main() {
	hello();
	bye();
	return 0;
}

编译test.c 并链接共享库libcommon.so

gcc -o test test.c -L. -lcommon
gcc首先链接共享库,再链接静态库

gcc -o test test.c -L. -lcommon -static
指定链接静态库

执行程序
./test

./test: error while loading shared libraries: libcommon.so
cannot open shared object file : No such file or directory
在这里插入图片描述当前目录不在系统搜索路径里,所以会报错。

添加共享库的加载路径

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

LD_LIBRARY_PATH可以添加环境中缺省的路径

在这里插入图片描述

如何找到共享库

  1. 把库拷贝到/usr/lib和/lib目录下
    不推荐,会跟系统库混乱

  2. 在LD_LIBRARY_PATH环境变量中添加库所在路径
    临时的,只对当前shell起作用

  3. 添加/etc/ld.so.conf.d/XXX.conf文件,执行ldconfig刷新
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/819515.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手机设置全局代理ip步骤

在互联网时代&#xff0c;隐私和安全问题备受关注。使用全局代理能够帮助我们保护个人信息&#xff0c;突破地理限制&#xff0c;并提高网络速度。但是&#xff0c;你是否对全局代理的安全性存有疑虑&#xff1f;而且&#xff0c;如何在手机上设置全局代理呢&#xff1f;今天就…

探索现代前端工程化工具与流程:提升开发效率和项目质量

文章目录 引言前端工程化的背景和发展1. 构建工具的出现2. 模块化开发3. 包管理工具的兴起4. 自动化测试和持续集成5. 组件化开发和前端框架的崛起 前端工程化对项目开发和团队协作的重要性 前端工程化基础前端工程化的定义和目标前端工程化的核心概念和原则 前端工程化工具与流…

nginx 301 Moved Permanently

1.nginx配置对比 --------------------------------------------- 2.postman特殊设置(postman在301情况下,会自动进行跳转,默认为自动跳转) 关闭自动跳转后 3. nginx 301分析 nginx 301情况如下 1.当location有最后一个斜杠,且proxy_pass后不带斜杠,会自动进行301跳转到带斜杠…

cad图像中的图标变成块的办法

在cad中想要一个半球图标&#xff0c;但是没有找到&#xff0c;只能自己修改原来的球机图标&#xff0c;重新画好后&#xff0c;进行“块”话操作&#xff0c;也就是把画好的图标变成“块”的办法&#xff1b; 1.把原来的“球机”图标经过多次“x”后&#xff0c;分解变成“线段…

Hadoop学习指南:探索大数据时代的重要组成——HDFS(上)

HDFS HDFS概述1.1 HDFS 产出背景及定义1&#xff09;HDFS产生背景2&#xff09;HDFS定义 1.2 HDFS 优缺点1.3 HDFS 组成架构1.4 HDFS 文件块大小&#xff08;面试重点&#xff09; 2.HDFS的Shell操作&#xff08;开发重点&#xff09;2.1 基本语法2.2 命令大全2.3 常用命令实操…

在云服务器上,clone github时报Connection timed outexit code: 128

文章目录 问题解决方案 问题 在执行pip install安装依赖时&#xff0c;需要clone github代码&#xff0c;此时报了Connection timed out&exit code: 128错误&#xff0c;原因是访问超时了&#xff0c;此时需要使用代理 fatal: unable to access https://github.com/hugg…

认识C语言

目录 1.C语言的发展历史 2.C语言的特点 3.C语言的应用领域 1.C语言的发展历史 C语言的发展历史可以追溯到20世纪60年代。在那个时候&#xff0c;计算机科学领域存在着多种编程语言&#xff0c;但它们在功能、效率和可移植性等方面存在一些限制。 C语言的起源可以追溯到贝尔实…

Python(五十四)列表元素的删除操作

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

接口和类的区别,超通俗化解释

接口告诉你&#xff0c;你可以有很多赚钱方式&#xff0c;接着你家几代人都通过各种方式赚钱&#xff0c;并把所有赚钱方式都告诉了你。

MAC下配置android-sdk

MAC下配置android-sdk 1、前提2、brew安装3、配置sdk 1、前提 安装好JDK安装brew 2、brew安装 brew install android-sdk brew install android-platform-tools检查是否安装成功 android3、配置sdk brew list android-sdk进入配置文件 sudo vim ~/.zshrc配置 export AND…

MySQL 数据库事务

前言 事务概念及特性 事务是指数据库操作的一个逻辑单位&#xff0c;它由一组被视为一个整体的数据库操作组成。 事务具有以下特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务中的所有操作要么全部成功执行&#xff0c;要么全部失败回滚。如果事务…

MySQL的使用——【初识MySQL】第二节

MySQL的使用——【初识MySQL】第二节 文章目录 MySQL环境变量的配置&#xff08;如使用Navicat可忽略&#xff09;使用命令行连接MySQL&#xff08;如使用Navicat可忽略&#xff09;步骤注意 NavicatNavicat的下载Navicat的使用连接MySQL新建表 总结总结 MySQL环境变量的配置&a…

新手入门吉他买什么好?千元内VEAZEN费森VZ200和恩雅X1pro综合评测,你会选新型材质HPL还是传统木吉他?

千元内入门吉他少不了VEAZEN费森VZ200单板系列和恩雅X1 PRO系列这两款热门系列&#xff0c;最近很多初学者朋友来私信&#xff0c;咨询这两款琴有什么优缺点&#xff0c;哪一款更值得初学者选购&#xff0c;那么今天&#xff0c;就以它们为本期的评测主角&#xff0c;全方位评测…

【《C# 10 和 .NET 6入门与跨平台开发(第6版)》——一本循序渐进的C#指南】

这个新版本对上一版做了全面修订&#xff0c;涵盖C# 10和.NET 6的所有新功能. 本书讨论面向对象编程、编写函数、测试函数、调试函数、实现接口以及继承类等主题&#xff1b;介绍.NET API&#xff0c;这些API可执行多种任务&#xff0c;如管理和查询数据&#xff0c;监视和改进…

vue组件方法 ref this.refs

在父组件中引入子组件&#xff0c;通常需要在父组件调用子组件的方法。就用到了组件方法 this.refs 使用前 需要在子组件模板定义 ref方法名 例如&#xff1a;红框所示 ref"name" //name为自定义名字 父组件使用时 只需要调用 this.$refs.name.子组件方法()&#x…

估值查看方法

估值查看方法 进入股票数据开放平台新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注脚注释也…

【C++】—— 多态常见的笔试和面试问题

序言&#xff1a; 在上期&#xff0c;我们对多态进行了详细的讲解。本期&#xff0c;我给大家带来的是关于有关多态常见的笔试和面试问题&#xff0c;帮助大家理解记忆相关知识点。 目录 &#xff08;一&#xff09;概念查考 &#xff08;二&#xff09;问答题 1、简述一下…

离线情况下解决pyinstaller生成的可执行文件过大问题

由于工作原因&#xff0c;我的电脑没法上传和下载文件&#xff0c;所以一开始选择了anaconda完成python的工作。使用了pyinstaller将脚本生成可执行文件。但是生成出来的exe巨大无比&#xff08;一个简单的脚本300多M&#xff0c;要花两分钟时间打开&#xff09;&#xff0c;于…

Mysql进阶(上) -- 存储引擎,索引

&#x1f442; Seasons in the Sun - Westlife - 单曲 - 网易云音乐 &#x1f448;目录 -- 查看左栏 目录 &#x1f418;存储引擎 &#x1f981;Mysql体系结构 &#x1f981;简介 &#x1f981;InnoDB介绍 &#x1f981;MyISAM和Memory &#x1f981;选择 &#x1f981…

[USACO06JAN] The Grove S

题目 思路 一眼bfs 为了保证bfs能够绕一个圈&#xff0c;我们将这个联通块的最下面的点的下方割去&#xff0c;如图 绿色的地方就是割去的地方&#xff0c;然后我们再加个判断&#xff0c;使bfs从起点出发转一圈&#xff0c;再把这条分割线的左右两边步数最小连起来&#xff…