【C语言从0到1之文件操作(FILE)】(原理 画图 举例 不信教不会你 不要放收藏夹落灰 学起来好嘛)

news2024/11/28 5:32:24
🕺作者: 迷茫的启明星
🎃专栏: 《数据库》 《C语言从0到1专栏》 《数据结构》 《C语言杂谈》
🏇分享喜欢的一句话:心如花木,向阳而生

前言

在我们的学习中,文件操作是被我们忽略,但用的时候又记忆模糊的内容,今天我带领大家来学习一下。

我之前也写过一篇,不过没这么详细,指路->《C语言FILE详解》,可查漏补缺。

1.为什么用文件?

我们在程序中怎么把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。

这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据

库等方式。

使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。

2. 什么是文件

磁盘上的文件是文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件数据文件(从文件功能的角度来分类的)。

2.1 程序文件

包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境

后缀为.exe)。

2.2 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,

或者输出内容的文件。

本篇讨论的是数据文件

以前我们学习C语言所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理

的就是磁盘上文件。

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

文件名包含3部分:文件路径+文件名主干+文件后缀

例如: c:\code\test.txt

为了方便起见,文件标识常被称为文件名。

3. 文件的打开和关闭

3.1 文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名

字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统

声明的,取名FILE.

例如,VS2022编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

struct _iobuf {
    char *_ptr;
    int  _cnt;
    char *_base;
    int  _flag;
    int  _file;
    int  _charbuf;
    int  _bufsiz;
    char *_tmpfname;
   };
typedef struct _iobuf FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,

使用者不必关心细节。

一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

下面我们可以创建一个FILE*的指针变量:

FILE* pf;//文件指针变量FILE* pf;

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变

量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联

的文件。

比如:

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

打开方式如下:

文件使用方式

含义

如果指定文件不存在

“r”(只读)

为了输入数据,打开一个已经存在的文本文件

出错

“w”(只写)

为了输出数据,打开一个文本文件

建立一个新的文件

“a”(追加)

向文本文件尾添加数据

建立一个新的文件

“rb”(只读)

为了输入数据,打开一个二进制文件

出错

“wb”(只写)

为了输出数据,打开一个二进制文件

建立一个新的文件

“ab”(追加)

向一个二进制文件尾添加数据

出错

“r+”(读写)

为了读和写,打开一个文本文件

出错

“w+”(读写)

为了读和写,建议一个新的文件

建立一个新的文件

“a+”(读写)

打开一个文件,在文件尾进行读写

建立一个新的文件

“rb+”(读写)

为了读和写打开一个二进制文件

出错

“wb+”(读写)

为了读和写,新建一个新的二进制文件

建立一个新的文件

“ab+”(读写)

打开一个二进制文件,在文件尾进行读和写

建立一个新的文件

实例代码:

#include <stdio.h>
#include <error.h>

int main()
{
    //FILE* pf = fopen("test.txt", "w");
    //如果本地的后缀名没有打开,这里文件输入test.txt,本地就是test.txt.txt
    //所以记得注意后缀名
    FILE* pf = fopen("test.txt", "w");
    if (NULL == pf)
    {
        perror("fopen");
        //fopen返回值为NULL则打开错误,这里的perror函数会打印错误信息,以提示错在哪里
        return 1;
    }
    //读取文件
    //....

    //关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

如果错误,运行结果为

4. 文件的顺序读写

功能

函数名

适用于

字符输入函数

fgetc

所有输入流

字符输出函数

fputc

所有输出流

文本行输入函数

fgets

所有输入流

文本行输出函数

fputs

所有输出流

格式化输入函数

fscanf

所有输入流

格式化输出函数

fprintf

所有输出流

二进制输入

fread

文件

二进制输出

fwrite

文件

下面我将举例带你们体会怎么运用:

fputc

int main()
{
    FILE* pf = fopen("test.txt", "a");
    if (NULL == pf)
    {
        perror("fopen");
        return 1;
    }
    //写文件
    /*fputc('a', pf);
    fputc('b', pf);
    fputc('c', pf);
    fputc('d', pf);*/
    char ch = 0;
    for (ch = 'a'; ch <= 'z'; ch++)
    {
        fputc(ch, pf);
    }

    //关闭文件
//    fclose(pf);
//    pf = NULL;

    return 0;
}

fgetc

int main()
{
    FILE* pf = fopen("test.txt", "r");
//这里我们在目录下已经建立了一个文件
    if (NULL == pf)
    {
        perror("fopen");
        return 1;
    }
    //读文件
    int ch = fgetc(pf);
    printf("%c\n", ch);

    ch = fgetc(pf);
    printf("%c\n", ch);

    ch = fgetc(pf);
    printf("%c\n", ch);

    //关闭文件
    fclose(pf);
    pf = NULL;

    return 0;
}

fputs

int main()
{
    FILE* pf = fopen("test.txt", "w");
    if (NULL == pf)
    {
        perror("fopen");
        return 1;
    }
    //写文件
    //测试写一行数据
    fputs("hello world\n", pf);
    fputs("hello bit\n", pf);
    return 0;
}

fgets

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (NULL == pf)
    {
        perror("fopen");
        return 1;
    }
    //读文件
    //测试一行数据
    char buf[20] = {0};
    fgets(buf, 20, pf);
    printf("%s", buf);
    fgets(buf, 20, pf);
    printf("%s", buf);
     //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

fputc fgetc 和fputs fgets总结

/*
 * 1,   int fgetc ( FILE * stream );
 *      int fputc ( FILE * stream );
 *      fgetc fputc是单个字符的获取和输入
 * 2,   char * fgets ( char * str, int num, FILE * stream );
 *      从文件中获得num个字符到str中
 *      int fputs ( const char * str, FILE * stream );
 *      将str中的字符放入文件中
 *      fgets(按行读取) fputs是字符串的获取和输出
 */

fprintf

struct S
{
    char name[20];
    int age;
    float score;
};

int main()
{
    struct S s = { "zhangsan", 20, 95.5 };
    FILE* pf = fopen("test.txt", "w");
    if (NULL == pf)
    {
        perror("fopen");
        return 1;
    }
    //格式化的将数据写入文件
    fprintf(pf, "%s %d %f\n", s.name, s.age, s.score);
    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

fscanf

struct S
{
    char name[20];
    int age;
    float score;
};
int main()
{
    struct S s = { 0 };
    FILE* pf = fopen("test.txt", "r");
    if (NULL == pf)
    {
        perror("fopen");
        return 1;
    }
    //格式化的读取文件
    fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
    //打印看数据
    printf("%s %d %f\n", s.name, s.age, s.score);

    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

fprintf fscanf总结

/*
 * 文件中格式化输入输出
 * 将文件视为输入输出流(类似键盘和屏幕)
 * 1,fprintf//将...输出到文件
 * int fprintf ( FILE * stream, const char * format, ... );
 * eg:fprintf(pf, "%s %d %f\n", s.name, s.age, s.score);
 *
 * 2,fscanf//从文件输入到...
 * int fscanf ( FILE * stream, const char * format, ... );
 * eg:fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
 */

输入输出流


struct S
{
    char name[20];
    int age;
    float score;
};

int main()
{
    struct S s = { 0 };
    fscanf(stdin, "%s %d %f", s.name, &(s.age), &(s.score));
    fprintf(stdout, "%s %d %f\n", s.name, s.age, s.score);
    return 0;
}

/*
效果:在键盘上打入什么字符就会输出什么字符
*/

输入输出流总结

/*什么是流?
 *通常来说计算机所说的流是指stream,
 *往往是对一种有序连续具有方向性的数据
 *(其单位可以是bit,byte,packet)的抽象描述。
 * 计算机中的流其实是一种信息的转换
 * 任何一个c语言程序运行时,默认打开三个流:stdin标准输入/stdout标准输出/stderr标准错误
 *
 * 输入输出流
 * stdin/stdout
 * 输入流就是把数据(键盘输入、鼠标、扫描仪等等外设设备)读入到内存(程序)中,
 * 输出流就是把内存(程序)中的数据输出到外设或其他地方,从文件角度简单总结就是,
 * 输入流就是读数据,输出流就是写数据。在这个过程中,始终把内存作为参考点。
 */

二进制读写函数

fwrite

struct S
{
    char name[20];
    int age;
    float score;
};
int main()
{
    struct S s = { "张三", 20, 98.5};
    FILE* pf = fopen("test.txt", "wb");
    if (NULL == pf)
    {
        perror("fopen");
        return 1;
    }
    //写文件
    fwrite(&s, sizeof(struct S), 1, pf);

    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

fread

struct S
{
    char name[20];
    int age;
    float score;
};
int main()
{
    struct S s = { 0};
    FILE* pf = fopen("test.txt", "rb");
    if (NULL == pf)
    {
        perror("fopen");
        return 1;
    }
    //读文件
    fread(&s, sizeof(struct S), 1, pf);
    printf("%s %d %f\n", s.name, s.age, s.score);

    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

fwrite fread总结

/*
 * 二进制写读文件
 * 1.fwrite     //以二进制写入文件
 * size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
 * eg:fwrite(&s, sizeof(struct S), 1, pf);
 * //1.给需要写入数据的地址 2.步长:一次读取的数据大小 3.个数 4.文件指针
 * 2.fread      //以二进制读取文件
 * size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
 * fread(&s, sizeof(struct S), 1, pf);
 * //与写入相同,不过是从文件中读取到s中
 *//*
 * 二进制写读文件
 * 1.fwrite     //以二进制写入文件
 * size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
 * eg:fwrite(&s, sizeof(struct S), 1, pf);
 * //1.给需要写入数据的地址 2.步长:一次读取的数据大小 3.个数 4.文件指针
 * 2.fread      //以二进制读取文件
 * size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
 * fread(&s, sizeof(struct S), 1, pf);
 * //与写入相同,不过是从文件中读取到s中
 */

sprintf sscanf

struct S
{
    char name[20];
    int age;
    float score;
};

int main()
{
    struct S s = {"zhangsan", 20, 98.5};
    char buf[100] = { 0 };
    sprintf(buf, "%s %d %f", s.name, s.age, s.score);
    printf("%s\n", buf);//按照字符串打印的

    struct S tmp = { 0 };
    sscanf(buf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));
    printf("%s %d %f\n", tmp.name, tmp.age, tmp.score);//打印结构体数据

    return 0;
}

sprintf sscanf总结

/*程序里xx的写读
 * 1.sprintf
 * int sprintf ( char * str, const char * format, ... );
 * eg:sprintf(buf, "%s %d %f", s.name, s.age, s.score);
 * 将s的各个部分 分别以"%s %d %f"的格式 写入buf
 * 2.sscanf
 *int sscanf ( const char * s, const char * format, ...);
 * eg:sscanf(buf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));
 *将buf的各个部分 分别以"%s %d %f"的格式 写入tmp
 * 其实可用于正则表达式
 */

对比一组函数:

scanf/fscanf/sscanf
printf/fprintf/sprintf

scanf--从键盘上读取格式化数据 适用于:stdin

printf--把数据(输出)到屏幕上 适用于:stout

fscanf--针对所有输入流的格式化的输入函数 适用于:stdin 打开的文件

fprintf--针对所有输出流的格式化的输出函数 适用于:stout 打开的文件

sscanf--从一个字符串中,还原出一个格式化的数据

sprintf--把格式化的数据,存放在(转换成)一个字符串

5.文件的随机读写

5.1 fseek ftell rewind

//在文件中已写入abcdef
int main()
{
    FILE*pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
    }
    else
    {
        int ch = fgetc(pf);
        printf("%c\n", ch);//a
        ch = fgetc(pf);
        printf("%c\n", ch);//b
        ch = fgetc(pf);
        printf("%c\n", ch);//c
        //abc
        //如果继续往下读,必然是d
        //但是我们调整一下,去读取:b
//        fseek(pf, -2, SEEK_CUR);
//        fseek(pf, 1, SEEK_SET);
        ch = fgetc(pf);
        printf("%c\n", ch);//b
        printf("%d\n", ftell(pf));
        rewind(pf);
        ch = fgetc(pf);
        printf("%c\n", ch);//a
    }
    return 0;
}

fseek ftell rewind总结

/* 1.修改偏移量(光标所在)
 * fseek
 * int fseek ( FILE * stream, long int offset, int origin );
 * eg:fseek(pf, -2, SEEK_CUR);  fseek(pf, 1, SEEK_SET);
 * //参数分别为文件指针,偏移量(左偏为负,右偏为正),origin为从首(SEEK_SET)或末(SEEK_CUR)开始偏移
 * 2.获得偏移量
 * ftell
 * long int ftell ( FILE * stream );
 * eg:printf("%d\n", ftell(pf));
 * 3.将偏移量设为初始值
 * rewind
 * void rewind ( FILE * stream );
 * eg:rewind(pf);
 */

6. 文本文件和二进制文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

一个数据在内存中存储,如果是字符则一律以ASCII形式存储,数值型数据可以用ASCII形势存储也可以用二进制形式存储。

比如:整数10000,

如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而

二进制形式输出,则在磁盘上只占4个字节。

测试

#include <stdio.h>
int main()
{
    int a = 10000;
    FILE* pf = fopen("test.txt", "wb");
    fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
    fclose(pf);
    pf = NULL;
    return 0;
}

先在解决方案中右击添加test.txt文件

右击test.txt文件

选择 二进制编辑器 确定即可

结果:

16进制显示

原理:小端存储,低位在低位 ,故看起来相反

7. 文件读取结束的判定

被错误使用的feof

牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束

而是用于当文件读取结束的时候,判断是读取失败(返回0)结束,还是遇到文件尾结束(返回非0值)。

ferror:返回值为非0则为出错为0则为没出错

1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )

例如:

  • fgetc 判断是否为 EOF .

  1. 如果成功,则返回读取的字符(提升为int值)。

返回类型是int,以适应表示失败的特殊值EOF:

  1. 如果位置指示符在文件末尾,该函数返回EOF并设置stream的EOF指示符(feof)。

c. 如果发生其他读取错误,该函数也返回EOF,但设置其错误指示器(ferror)。

  • fgets 判断返回值是否为 NULL .

  1. 如果成功,函数返回str。

  1. 如果在试图读取字符时遇到了文件结束符,则设置eof (feof)。

  1. 如果这是在读取任何字符之前发生的,则返回的指针是null指针(str的内容保持不变)。

  1. 如果发生读错误,则设置错误指示器(ferror),并返回null指针(但str指向的内容可能已经改变)。

2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

例如:

  • fread判断返回值是否小于实际要读的个数。

文本文件举例:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
    }
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
    {
        putchar(c);
    }

    //判断是什么原因结束的
    if (ferror(fp))
    puts("I/O error when reading");
    else if (feof(fp))
    puts("End of file reached successfully");
    fclose(fp);
}

二进制文件举例:

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
  double a[SIZE] = {1.,2.,3.,4.,5.};
  FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
  fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
  fclose(fp);
  double b[SIZE];
  fp = fopen("test.bin","rb");
  size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
  if(ret_code == SIZE) {
    puts("Array read successfully, contents: ");
    for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
    putchar('\n');
 } else { // error handling
   if (feof(fp))
     printf("Error reading test.bin: unexpected end of file\n");
   else if (ferror(fp)) {
     perror("Error reading test.bin");
   }
 }
fclose(fp);
}

8. 文件缓冲区

ANSIC 标准采用“缓冲文件系统”处理的数据文件的,

所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”

从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。

如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓

冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。

缓冲区的大小根据C编译系统决定的。

#include <stdio.h>
#include <windows.h>
//Clion WIN11 环境测试
int main()
{
    FILE* pf = fopen("test.txt", "w");
    fputs("abcdef", pf);//先将代码放在输出缓冲区
    printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
    Sleep(10000);//10秒
    printf("刷新缓冲区\n");
    fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
    //注:fflush 在高版本的VS上不能使用了
    printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
    Sleep(10000);

    fclose(pf);
    //注:fclose在关闭文件的时候,也会刷新缓冲区
    pf = NULL;
    return 0;
}

注意事项

/*
 * 输入的数据先在缓冲区中,满了或者主动刷新才会把数据输入文件
 * fflush-刷新缓冲区
 * fclose-关闭文件也会刷新缓冲区
 *因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文
 *件。如果不做,可能导致读写文件的问题。
 */

后记

一个多月没有写博客记录了,因为实在是写得太慢了,以后会继续坚持的!!!

希望和大家一起进步!!!

点个赞再走吧~~~🐧 🐧 🐧

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

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

相关文章

NodeJS 与第三方模块 mysql(基本操作)

文章目录参考描述mysql 模块连接数据库检测基本操作查询数据与代码分离原则占位符插入另一种姿态修改另一种姿态删除标记删除参考 项目描述哔哩哔哩黑马程序员搜索引擎Bing 描述 项目描述NodeJSv18.13.0nodemon2.0.20MySQL5.7.40mysql2.18.1 mysql 模块 npm&#xff08;Node…

Linux——进程

目录 冯诺依曼体系结构 操作系统(Operator System) 概念 设计OS的目的 定位 如何理解 "管理" 总结 系统调用和库函数概念 承上启下 进程 基本概念 描述进程-PCB task_struct-PCB的一种 task_ struct内容分类 组织进程 查看进程 通过系统调用获取进程…

Pycharm使用Git进行版本控制(自建远端Git仓库)

目录本地Git安装远端Git仓库搭建在Pycharm中使用Git进行版本控制设置Git可执行文件路径创建本地Git仓库设置远端Git仓库提交及推送本地Git安装 安装本地Git用于被Pycharm调用&#xff0c;安装方法参考以下博客&#xff1a; Git 的下载与安装_作者&#xff1a;fengzhx0820 远端…

四轮两驱小车(四):STM32驱动5路灰度传感器PID循迹

目录 前言&#xff1a; 小车效果展示&#xff1a; 5路数字灰度传感器&#xff1a; 巡线思路&#xff1a; 加入PID调节的代码&#xff1a; 前言&#xff1a; 之前买了一批5路灰度传感器&#xff0c;想用这传感器进行循迹&#xff0c;无奈网上和官方的资料提供的还是比较少&a…

ARM X210 官方 uboot 配置编译实践

一、X210官方uboot配置编译实践1 1. 找到官方移植好的 uboot&#xff08;BSP 概念&#xff09; (1) 源头的源代码是 uboot 官网下载的。这个下载的源代码可能没有你当前使用的开发板的移植&#xff0c;甚至找不到当前开发板使用的 SoC 对应的移植版本。 (2) SoC 厂商在推出一…

分享145个ASP源码,总有一款适合您

ASP源码 分享145个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 145个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1gxm3rFFLu8pUhVncQga6-g?pwd7n85 提取码&#x…

HJ56、HJ58、JZ4、JZ6、JZ15、JZ17几道题

文章目录HJ56 完全数计算题目描述&#xff1a;具体实现&#xff1a;HJ58 输入n个整数&#xff0c;输出其中最小的k个题目描述&#xff1a;具体实现&#xff1a;JZ4 二维数组中的查找题目描述&#xff1a;具体实现&#xff1a;JZ6 从尾到头打印链表题目描述&#xff1a;具体实现…

springboot文件上传,单文件上传和多文件上传,以及数据遍历和回显

springboot文件上传&#xff0c;单文件上传和多文件上传项目结构及pom.xml创建文件表单页面编写javabean编写controller映射MultipartFile类RequestPart注解controller代码application.properties中的文件上传配置遍历数据显示页面运行显示项目结构及pom.xml pom.xml: <dep…

SQL用法详解补充

本文是对上次“SQL用法详解”的一些补充&#xff0c;一些基本操作可以点击链接查看 目录 一.对表结构的常用操作 查看表结构格式 修改表结构格式 1.修改列名和类型 2.修改添加列 3.修改表删除列 4.修改表名 5.数据删除 二.总结 三.实例 解决 完整代码 一.对表结构的常用操…

TIA博途中启用或禁用DP从站或PROFINET IO设备的具体方法

TIA博途中启用或禁用DP从站或PROFINET IO设备的具体方法 在实际项目中我们会遇到这样的问题, 例如:硬件组态中配置了一个控制器和3个 PN IO设备,但是最后只用到了2个PN IO设备,这样控制器一侧无法连接到第3个PN IO设备时,CPU会产生报警,PLC的Error指示灯会一直闪烁。 那么…

蓝桥杯2021省赛Python

蓝桥杯2021省赛Python 不得不说2021的比2020的难 1.卡片 很明显&#xff0c;最先没的肯定是1或者0&#xff0c;我们只要统计到谁会消耗2022个1或者0就好了 if __name__ __main__:res1 0res0 0for i in range(1,100000):i str(i)res1 i.count(1)res0 i.count(0)if res1…

[Rust笔记] 规则宏的“卫生保健”

规则宏代码的“卫生保健”规则宏mbe即是由macro_rules!宏所定义的宏。它的英文全称是Macro By Example。相比近乎“徒手攀岩”的Cpp模板元编程&#xff0c;rustc提供了有限的编译时宏代码检查功能&#xff08;名曰&#xff1a;Mixed Hygiene宏的混合保健&#xff09;。因为rust…

pointcovn 阅读笔记

各种点云采样算法 https://blog.csdn.net/weixin_41485242/article/details/107150963 Inverse Density 1.2 Inverse Density Importance Sampling (IDIS): 这个也比较好理解&#xff0c;简而言之就是根据每个点的密度来对其重新进行排序&#xff0c;尽可能地保留密度比较低的地…

python第九章 异常笔记

和Java类似程序运行有异常的时候&#xff0c;服务器会采用系统默认的异常处理机制&#xff1a;返回信息&#xff0c;终止程序。异常的类型&#xff1a;常见异常类型&#xff1a;1.NameError&#xff1a;访问了未定义的变量2.IndexError&#xff1a;越界访问3.AttributeError&am…

网络原理-网络发展史和通信基础

目录 1.网络发展史 面向终端的计算机网络 计算机网络阶段(局域网LAN) 组网方式 计算机网络互联阶段(广域网WAN) 2.通信基础 IP地址 端口号 网络协议 协议的作用 知名协议的默认端口 协议分层 分层的作用 OSI七层模型 TCP/IP五层模型 网络设备所在分层 网络分层…

《数据结构》八大排序和拓展的排序(详细教学并提供多种版本、动态图分析)

今天&#xff0c;我将带来数据结构的排序算法&#xff0c;排序算法作为校招中常考知识点之一&#xff0c;我们必须要熟练的掌握它,对自己提出高要求&#xff0c;才能有高回报。 目录排序的概念和应用内部排序和外部排序排序算法需要掌握的知识插入排序1.直接插入排序2.希尔排序…

【教程】Python实时检测CPU和GPU的功耗

目录 前言 GPU功耗检测方法 CPU功耗检测方法 sudo的困扰与解决 完整功耗分析示例代码 转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 前言 相关一些检测工具挺多的&#xff0c;比如powertop、powerstat、s-tui等。但如何通过代码的方式来实时检测&#xf…

Unsafe Fileupload-基础篇(文件上传绕过技巧与upload-labs靶场)

数据来源 本文仅用于信息安全的学习&#xff0c;请遵守相关法律法规&#xff0c;严禁用于非法途径。若观众因此作出任何危害网络安全的行为&#xff0c;后果自负&#xff0c;与本人无关。 文件上传基础 01 什么是文件上传 02 文件上传产生漏洞的原因 03 文件上传漏洞危害 0…

济人药业更新招股书:计划在A股上市,中成药业务收入持续下滑

近日&#xff0c;安徽济人药业股份有限公司&#xff08;下称“济人药业”&#xff09;递交预披露更新招股书&#xff0c;准备在上海证券交易所主板上市。据贝多财经了解&#xff0c;济人药业于2022年7月1日递交上市申请&#xff0c;此次更新了截至2022年6月30日的财务数据等信息…

Android深入系统完全讲解(42)

红色部分 pc 000007cc 代表当前 pc 指向的位置。libnative-lib.so 代表在哪个库里面。于是我 们就需要知道&#xff0c;libnative-lib.so 库的 pc 000007cc 偏移位置&#xff0c;是个什么代码。 我们从 NDK 开发包中找到 D:\android-ndk-r19c\toolchains\arm-linux-androideabi…