Linux_fileio學習

參考韋東山老師教程:https://www.bilibili.com/video/BV1kk4y117Tu?p=12

目錄

    • 1. 文件IO函數分類
    • 2. 函數原型
      • 2.1 系統調用接口
      • 2.2 標準IO接口
    • 3. fileio內部機制
      • 3.1 系統調用接口內部流程
      • 3.1 dup函數使用
      • 3.2 dup2函數使用
    • 4. open file
      • 4.1 open實例
      • 4.2 open函數分析
    • 5. create file
      • 5.1 create實例
      • 5.2 create分析
    • 6. write file
      • 6.1 write實例
      • 6.2 write分析
    • 7. read file
      • 7.1 read實例
      • 7.2 read分析
    • 8.簡單實例——處理.csv表格

1. 文件IO函數分類

在 Linux 上操作文件時,有兩套函數:標準 IO、系統調用 IO。
標準 IO 的相關函數是:fopen/fread/fwrite/fseek/fflush/fclose 等 。
系統調用 IO 的相關函數是:open/read/write/lseek/fsync/close。
這 2 種 IO 函數的差別如下圖所示:

在這里插入圖片描述

2. 函數原型

2.1 系統調用接口

open/read/write/lseek/fsync/close 這幾個函數的用法:

函數名函數原型描述
open#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);
作用:打開或者創建一個文件
pathnam:文件路徑名,或者文件名
flags:表示打開文件所采用的操作
O_RDONLY:只讀模式
O_WRONLY:只寫模式
O_RDWR:可讀可寫
O_APPEND 表示追加,如果原來文件里面有內容,則這次寫入會寫在文件的最末尾
O_CREAT 表示如果指定文件不存在,則創建這個文件
O_EXCL 表示如果要創建的文件已存在,則出錯,同時返回 -1,并且修改 errno 的值
O_TRUNC 表示截斷,如果文件存在,并且以只寫、讀寫方式打開,則將其長度截斷為 0
O_NOCTTY 如果路徑名指向終端設備,不要把這個設備用作控制終端
O_NONBLOCK 如果路徑名指向 FIFO/塊文件/字符文件,則把文件的打開和后繼 I/O 設置為非阻塞模式(nonblocking mode)
O_DSYNC 等待物理 I/O 結束后再 write。在不影響讀取新寫入的數據的前提下,不等待文件屬性更新
O_RSYNC read 等待所有寫入同一區域的寫操作完成后再進行
O_SYNC 等待物理 I/O 結束后再 write,包括更新文件屬性的I/O
mode: 文件訪問權限的初始值
read#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
作用:從給定的文件描述符指定的文件中,讀取 count 個字節的數據,存放至 buf 中。
fd:指定要讀寫的文件描述符
buf:緩沖區,一般是一個數組,用于存放讀取的內容
count:一次要讀取的最大字節數
write#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
作用:將 buf 中的 count 字節數據寫入指定文件描述符的文件中
fd:指定要寫入的文件描述符
buf:緩沖區,一般是一個數組,讀取存放于該數組的內容存放于文件中
count:要寫入的實際字節數
dup
dup2
dup3
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
int dup3(int oldfd, int newfd, int flags);
作用:復制文件描述符,就是兩個文件句柄指向同一個文件描述符,這兩個文件句柄共享文件偏移地址、狀態
oldfd:被復制的文件句柄
newfd:復制得到的文件句柄
注意:dup 函數返回的文件句柄是“未使用的最小文件句柄”,dup2 可以指定復制得到的文件句柄為 newfd,dup3 跟 dup2 類似,flags 參數必要么是 0,要么是 O_CLOEXEC
lseek#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
作用:重新定位讀/寫文件偏移
fd:指定要偏移的文件描述符
offset:文件偏移量
whence:開始添加偏移 offset 的位置
SEEK_SET,offset 相對于文件開頭進行偏移
SEEK_CUR,offset 相對文件當前位置進行偏移
SEEK_END,offset 相對于文件末尾進行偏移
fsync#include <unistd.h>
int fsync(int fd);
作用:同步內存中所有已修改的文件數據到儲存設備
fd:指定要同步的文件描述符
close#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int close(int fd);
作用:關閉已打開的文件

2.2 標準IO接口

fopen/fread/fwrite/fseek/fflush/fclose 這幾個函數的用法:

函數名函數原型描述
fopen#include<stdio.h>
FILE *fopen(const char *filename, const char *mode);
作用:打開或者創建一個文件
filename:文件路徑名,或者文件名
mode:文件的訪問模式
r 打開一個用于讀取的文件。該文件必須存在。
w 創建一個用于寫入的空文件。如果文件名稱與已存在的文件相同,則會刪除已有文件的內容,文件被視為一個新的空文件。
a 追加到一個文件。寫操作向文件末尾追加數據。如果文件不存在,則創建文件。
r+ 打開一個用于更新的文件,可讀取也可寫入。該文件必須存在。
w+ 創建一個用于讀寫的空文件。
a+ 打開一個用于讀取和追加的文件。
fread#include<stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
作用:從給定流 stream 讀取數據到 ptr 所指向的數組中
ptr:指向帶有最小尺寸 size*nmemb 字節的內存塊的指針
size:這是要讀取的每個元素的大小,以字節為單位
nmemb:元素的個數,每個元素的大小為 size 字節
stream:這是指向 FILE 對象的指針,該 FILE 對象指定了一個輸入流
fwrite#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
作用:把 ptr 所指向的數組中的數據寫入到給定流 stream 中
ptr:這是指向要被寫入的元素數組的指針
size:這是要被寫入的每個元素的大小,以字節為單位
nmemb:這是元素的個數,每個元素的大小為 size 字節
stream:這是指向 FILE 對象的指針,該 FILE 對象指定了一個輸出流
fseek#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence);
作用:設置流 stream 的文件位置為給定的偏移 offset
stream:這是指向 FILE 對象的指針,該 FILE 對象標識了流
offset:這是相對 whence 的偏移量,以字節為單位
whence:表示開始添加偏移 offset 的位置
SEEK_SET,offset 相對于文件開頭進行偏移
SEEK_CUR,offset 相對文件當前位置進行偏移
SEEK_END,offset 相對于文件末尾進行偏移
fflush#include <stdio.h>
int fflush(FILE *stream);
作用:刷新流 stream 的輸出緩沖區
stream:這是指向 FILE 對象的指針,該 FILE 對象指定了一個緩沖流
fclose#include <stdio.h>
int fclose(FILE *stream);
作用:關閉流 stream,且刷新其緩沖區
stream:這是指向 FILE 對象的指針,該 FILE 對象指定了要被關閉的流

3. fileio內部機制

3.1 系統調用接口內部流程

在Linux操作系統中,用戶態(User Mode)和內核態(Kernel Mode)是兩種不同的處理器運行模式,它們代表了程序執行時的不同權限級別和對系統資源訪問的能力。

用戶態(User Mode)

  • 應用程序運行的正常狀態。在用戶態下,進程可以執行的指令受到限制,主要目的是保護系統資源和保持系統穩定性。應用程序不能直接訪問硬件資源(如內存、CPU寄存器、I/O設備等)或者執行特權指令。
  • 用戶態下的進程運行在較低的CPU特權級別(通常是Ring 3),這意味著它們沒有直接操作硬件的權限。
  • 當應用程序需要執行某些特權操作(如讀寫文件、網絡通信、分配內存等)時,它必須通過系統調用(system call)向操作系統內核發出請求,這時會從用戶態轉換到內核態。

內核態(Kernel Mode)

  • 操作系統內核運行的狀態,擁有最高權限。內核可以直接訪問所有硬件資源,執行任意指令,并且可以改變處理器狀態。
  • 在內核態下,進程運行在最高的CPU特權級別(Ring 0),享有對所有系統資源的完全控制權。
  • 內核態負責管理硬件資源、調度進程、處理中斷和系統調用等核心功能。當系統調用發生時,處理器從用戶態切換到內核態,執行內核代碼完成請求的服務,然后返回用戶態繼續執行應用程序。
  • 在內核態下,還有一種特殊的上下文稱為“中斷上下文”,這是當硬件中斷發生時,CPU暫停當前任務,轉而執行中斷處理程序的狀態。

簡而言之,用戶態保證了應用程序的安全隔離,而內核態則提供了對系統資源的直接訪問和管理能力,兩者之間的轉換是操作系統管理和控制資源的關鍵機制。

fileio也是一樣,系統調用接口open/read/write/lseek/fsync/close就是用戶態應用程序能夠調用的函數,這些接口是由GLIBC(GNU C Library)提供的,用來訪問Linux的內核服務。

GLIBC提供的open/read/write/lseek/fsync/close函數訪問Linux的步驟:

  • 當使用open/read/write/lseek/fsync/close函數時,會設置異常原因,如open、read等,再調用匯編指令swi/svc來觸發一個異常,并攜帶異常原因;
  • CPU發現異常后會分辨異常原因,(假設是open函數)在sys_call_table[NR_open]中分辨異常原因后,會在fs/open.c文件中調用SYSCALL_DEFINE3即sys_open函數執行open文件操作。

在這里插入圖片描述

其中

ABI(Application Binary Interface):應用二進制接口

OABI(Old ABI):舊的應用二進制接口

EABI(Embedded ABI):“E”代表“Embedded”,表示ARM嵌入式系統設計的一種新的ABI規范

sys_call_table的函數指針數組:

在這里插入圖片描述

fs/open.c中SYSCALL_DEFINE3函數

在這里插入圖片描述

3.1 dup函數使用

dup函數使用代碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>int main(int argc, char **argv)
{char buf[10];char buf2[10];if (argc != 2){printf("Usage: %s <file>\n", argv[0]);return -1;}int fd = open(argv[1], O_RDONLY);int fd2 = open(argv[1], O_RDONLY);int fd3 = dup(fd);printf("fd = %d\n", fd);printf("fd2 = %d\n", fd2);printf("fd3 = %d\n", fd3);if (fd < 0 || fd2 < 0 || fd3 < 0){printf("can not open %s\n", argv[1]);return -1;}read(fd, buf, 1);read(fd2, buf2, 1);printf("data get from fd : %c\n", buf[0]);printf("data get from fd2: %c\n", buf2[0]);read(fd3, buf, 1);printf("data get from fd3: %c\n", buf[0]);return 0;
}

上傳到Ubuntu后編譯運行:

在這里插入圖片描述

3.2 dup2函數使用

dup2函數使用代碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>/** ./dup2 1.txt* argc    = 2* argv[0] = "./dup2"* argv[1] = "1.txt"*/int main(int argc, char **argv)
{int fd;if (argc != 2){printf("Usage: %s <file>\n", argv[0]);return -1;}fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0777);if (fd < 0){printf("can not open file %s\n", argv[1]);printf("errno = %d\n", errno);printf("err: %s\n", strerror(errno));perror("open");}else{printf("fd = %d\n", fd);}/* fd=1的文件是系統標準輸出文件,如printf*/dup2(fd, 1);printf("hello, world\n");  /* 打印到fd=1的文件    */return 0;
}

上傳到Ubuntu后編譯運行:

在這里插入圖片描述

4. open file

4.1 open實例

open代碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>/** ./open 1.txt* argc    = 2* argv[0] = "./open"* argv[1] = "1.txt"*/int main(int argc, char **argv)
{int fd;if (argc != 2){printf("Usage: %s <file>\n", argv[0]);return -1;}fd = open(argv[1], O_RDWR);if (fd < 0){printf("can not open file %s\n", argv[1]);printf("errno = %d\n", errno);printf("err: %s\n", strerror(errno));perror("open");}else{printf("fd = %d\n", fd);}while (1){sleep(10);}close(fd);return 0;
}

上傳到Ubuntu后編譯運行:

在這里插入圖片描述

補充:error變量、strerror函數、perror函數

errno:errno h頭文件定義了整數變量,它在系統調用和一些庫函數在發生錯誤時被設置,以指示出錯的地方。

在這里插入圖片描述

在man errno中能夠找到對應的錯誤碼:

在這里插入圖片描述

strerror:函數 char *strerror(int errnum); 指向errnum對應的字符串,使用 printf(“err: %s\n”, strerror(errno)); 就能打印出對應的錯誤碼含義:

在這里插入圖片描述

perror:函數 void perror(const char *s); 打印參數字符串s,后跟冒號和空白,然后顯示一條與當前值oferrno相對應的錯誤消息和一行新行:

在這里插入圖片描述

4.2 open函數分析

使用編寫的open應用程序在后臺分別打開2個文件,發現獲得的文件句柄fd都是3,查看2個后臺正在運行的程序進程,發現2個進程都有4個文件句柄,其中fd 0表示系統標準輸入(stdin),例如scanffd 1表示系統標準輸出(stdout),例如printffd 2表示標準錯誤(stderr),存放錯誤信息;fd 3是應用程序剛剛打開的文件句柄:

在這里插入圖片描述

由此可知,先后2次使用open函數在后臺打開文件,每次執行open時分配一個進程號,2次open屬于不同的進程,所以2次open文件返回的文件句柄都是3并不沖突。

在open的執行過程中,文件句柄fd是如何與進程號關聯起來的?需要根據代碼進行分析:

由3.1章節可知,調用open函數時最終調用到fs/open.c中do_sys_open內核函數來打開文件:

在這里插入圖片描述

繼續分析fd_install函數:

在這里插入圖片描述

其中current結構體為什么是task_struct結構體還需要后續再分析。

查看task_struct結構體,在task_struct結構體中有files_struct結構體:

在這里插入圖片描述

files_struct結構體中會有一個fdtab:

在這里插入圖片描述

fdtable結構體中會有file結構體,保存文件句柄fd:

在這里插入圖片描述

因此對于每次執行的open文件操作都會創建一個task_struct結構體,在對應的fdtable中會保存此進程打開的文件句柄fd:

在這里插入圖片描述

在fdtable的file結構體中會有一個f_pos保存當前偏移位置,在調用lseek、read、write 都會更新f_pos的位置:

在這里插入圖片描述

5. create file

5.1 create實例

create代碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>/** ./create 1.txt* argc    = 2* argv[0] = "./open"* argv[1] = "1.txt"*/int main(int argc, char **argv)
{int fd;if (argc != 2){printf("Usage: %s <file>\n", argv[0]);return -1;}fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0777);if (fd < 0){printf("can not open file %s\n", argv[1]);printf("errno = %d\n", errno);printf("err: %s\n", strerror(errno));perror("open");}else{printf("fd = %d\n", fd);}while (1){sleep(10);}close(fd);return 0;
}

上傳到Ubuntu后編譯運行:

在這里插入圖片描述

5.2 create分析

“open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0777);”參考2.1章節系統調用接口中open描述,第2個參數是以可讀可寫、若文件不存在則創建文件、截取文件的方式open文件,第3個參數是open的文件權限是777,但是創建的文件2.txt權限并不是777,而是775,原因是系統的umask是2,所以其他用戶的寫權限是默認被關閉的

在這里插入圖片描述

在這里插入圖片描述

create是使用open函數實現的,在do_sys_open中調用build_open_flags打開文件是會使用到flags和mode參數:

在這里插入圖片描述

操作與open函數基本相同。

6. write file

6.1 write實例

write代碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>/** ./write 1.txt  str1 str2* argc    = 2* argv[0] = "./open"* argv[1] = "1.txt"*/int main(int argc, char **argv)
{int fd;int i;int len;if (argc < 3){printf("Usage: %s <file> <string1> <string2> ...\n", argv[0]);return -1;}fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd < 0){printf("can not open file %s\n", argv[1]);printf("errno = %d\n", errno);printf("err: %s\n", strerror(errno));perror("open");}else{printf("fd = %d\n", fd);}for (i = 2; i < argc; i++){len = write(fd, argv[i], strlen(argv[i]));if (len != strlen(argv[i])){perror("write");break;}write(fd, "\r\n", 2);}close(fd);return 0;
}

上傳到Ubuntu后編譯運行:

在這里插入圖片描述

write_in_pos代碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>/** ./write 1.txt  str1 str2* argc    = 2* argv[0] = "./open"* argv[1] = "1.txt"*/int main(int argc, char **argv)
{int fd;int i;int len;if (argc != 2){printf("Usage: %s <file>\n", argv[0]);return -1;}fd = open(argv[1], O_RDWR | O_CREAT, 0644);if (fd < 0){printf("can not open file %s\n", argv[1]);printf("errno = %d\n", errno);printf("err: %s\n", strerror(errno));perror("open");}else{printf("fd = %d\n", fd);}printf("lseek to offset 3 from file head\n");lseek(fd, 3, SEEK_SET);write(fd, "123", 3);close(fd);return 0;
}

上傳到Ubuntu后編譯運行:

在這里插入圖片描述

6.2 write分析

搜索SYSCALL_DEFINE3調用write的函數:

在這里插入圖片描述

分析SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)函數過程:

在這里插入圖片描述

7. read file

7.1 read實例

read代碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>/** ./read 1.txt* argc    = 2* argv[0] = "./read"* argv[1] = "1.txt"*/int main(int argc, char **argv)
{int fd;int i;int len;unsigned char buf[100];if (argc != 2){printf("Usage: %s <file>\n", argv[0]);return -1;}fd = open(argv[1], O_RDONLY);if (fd < 0){printf("can not open file %s\n", argv[1]);printf("errno = %d\n", errno);printf("err: %s\n", strerror(errno));perror("open");}else{printf("fd = %d\n", fd);}/* 讀文件/打印 */while (1){len = read(fd, buf, sizeof(buf)-1);if (len < 0){perror("read");close(fd);return -1;}else if (len == 0){break;}else{/* buf[0], buf[1], ..., buf[len-1] 含有讀出的數據* buf[len] = '\0'*/buf[len] = '\0';printf("%s", buf);}}close(fd);return 0;
}

上傳到Ubuntu后編譯運行:

在這里插入圖片描述

7.2 read分析

搜索SYSCALL_DEFINE3調用read的函數:

在這里插入圖片描述

分析SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)函數過程:

在這里插入圖片描述

8.簡單實例——處理.csv表格

背景描述:創建一個score.csv表格,文件中包含張三、李四、王五同學的語文、數學、英語分數。

處理步驟:

  • 打開score.csv表格
  • 通過score.csv表格中的分數計算出每位同學的總分并對分數進行評價,最終結果輸出到指定的表格文件(result.csv)中(評價標準:3科總分>=270為A+等級、3科總分>=240為A等級、其余成績為B等級)

在這里插入圖片描述

補充:使用notepad++打開score.csv表格,每一列之間用’,'隔開,每一行之間用回車換行隔開

在這里插入圖片描述

處理score.csv表格數據時需要先讀取score.csv表格中的數據到一個buf中,此時可以用回車換(0x0d和0x0a)作為讀取每一行數據的結束標志,參考函數read_line()。

代碼:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>/* 返回值: n表示讀到了一行數據的數據個數(n >= 0)*         -1(讀到文件尾部或者出錯)*/
static int read_line(int fd, unsigned char *buf)
{/* 循環讀入一個字符 *//* 如何判斷已經讀完一行? 讀到0x0d, 0x0a */unsigned char c;int len;int i = 0;int err = 0;while (1){len = read(fd, &c, 1);if (len <= 0){err = -1;break;}else{if (c != '\n' && c != '\r'){buf[i] = c;i++;}else{/* 碰到回車換行   */err = 0;break;}}}buf[i] = '\0';if (err && (i == 0)){/* 讀到文件尾部了并且一個數據都沒有讀進來 */return -1;}else{return i;}
}void process_data(unsigned char *data_buf, unsigned char *result_buf)
{/* 示例1: data_buf = ",語文,數學,英語,總分,評價" *        result_buf = ",語文,數學,英語,總分,評價" * 示例2: data_buf = "張三,90,91,92,," *        result_buf = "張三,90,91,92,273,A+" **/char name[100];int scores[3];int sum;char *levels[] = {"A+", "A", "B"};int level;if (data_buf[0] == 0xef) /* 對于UTF-8編碼的文件,它的前3個字符是0xef 0xbb 0xbf */{strcpy(result_buf, data_buf);}else{sscanf(data_buf, "%[^,],%d,%d,%d,", name, &scores[0], &scores[1], &scores[2]);//printf("result: %s,%d,%d,%d\n\r", name, scores[0], scores[1], scores[2]);//printf("result: %s --->get name---> %s\n\r", data_buf, name);sum = scores[0] + scores[1] + scores[2];if (sum >= 270)level = 0;else if (sum >= 240)level = 1;elselevel = 2;sprintf(result_buf, "%s,%d,%d,%d,%d,%s", name, scores[0], scores[1], scores[2], sum, levels[level]);//printf("result: %s", result_buf);}
}/** ./process_excel data.csv  result.csv* argc    = 3* argv[0] = "./process_excel"* argv[1] = "data.csv"* argv[2] = "result.csv"*/int main(int argc, char **argv)
{int fd_data, fd_result;int i;int len;unsigned char data_buf[1000];unsigned char result_buf[1000];if (argc != 3){printf("Usage: %s <data csv file> <result csv file>\n", argv[0]);return -1;}fd_data = open(argv[1], O_RDONLY);if (fd_data < 0){printf("can not open file %s\n", argv[1]);perror("open");return -1;}else{printf("data file fd = %d\n", fd_data);}fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);if (fd_result < 0){printf("can not create file %s\n", argv[2]);perror("create");return -1;}else{printf("resultfile fd = %d\n", fd_result);}while (1){/* 從數據文件里讀取1行 */len = read_line(fd_data, data_buf);if (len == -1){break;}//if (len != 0)//    printf("line: %s\n\r", data_buf);if (len != 0){/* 處理數據 */process_data(data_buf, result_buf);/* 寫入結果文件 *///write_data(fd_result, result_buf);write(fd_result, result_buf, strlen(result_buf));write(fd_result, "\r\n", 2);}}close(fd_data);close(fd_result);return 0;
}

代碼及score.csv文件上傳到ubuntu后運行效果:

在這里插入圖片描述

將result.csv文件傳回到windows打開:

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/39643.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/39643.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/39643.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Cocos如何跟Android通信?

點擊上方億元程序員+關注和★星標 引言 Cocos如何跟Android通信 大家好,相信小伙伴們通過閱讀筆者前幾期的文章**《Cocos打安卓包打不出來?看看這個》,對Cocos**如何打安卓包有了一定的了解。 但是,除了把安卓包打出來,另外還有一個重要的就是要能夠調用安卓提供的Java方…

華為HCIP Datacom H12-821 卷21

1.單選題 以下關于PIM-SM中SPT切換的描述,錯誤的是哪一項? A、若所有組播流量都經過RP路由器,則RP路由器可能成為數據轉發的瓶頸 B、SPT路徑最短,轉發性能更優 C、SPT 切換完成后,組播流量依然經過 ReT 樹 D、RPT 樹可能不是組播流量轉發的最優路徑 正確答案: C 解析…

【AI原理解析】—K近鄰(KNN)原理

目錄 一、算法概述 二、算法原理 1. 數據集準備 2. 輸入新數據 3. 距離計算 4. 選擇K個最近鄰 5. 預測 三、關鍵要素 1. K值的選擇 2. 距離度量方法 3. 數據預處理 四、算法優缺點 優點 缺點 五、總結 KNN&#xff08;K-Nearest Neighbors&#xff0c;K最近鄰&a…

[教程]Gitee保姆級圖文使用教程

我們在日常的工作過程中經常會遇到&#xff0c;家里和公司資料文件同步的問題&#xff0c;以及項目開發過程中的協作問題。Git就完美的解決了這些問題&#xff0c;但是由于 Git國外服務器的原因平時網絡太慢了&#xff0c;不過還好有國內的托管平臺Gitee&#xff08;碼云&#…

「C++系列」C++ 變量類型

文章目錄 一、C 變量類型1. 基本數據類型2. 復合數據類型3. 類型修飾符 二、C 變量定義案例 1: 基本類型變量的定義和初始化案例 2: 數組的定義和使用案例 3: 結構體&#xff08;Struct&#xff09;的定義和使用案例 4: 指針的定義和使用案例 5: 類的定義和使用&#xff08;面向…

五、removeClosedPointCloud

五、removeClosedPointCloud 主要功能: removeClosedPointCloud 函數用于過濾掉點云中距離傳感器(例如激光雷達)太近的點。這些點可能會引入噪聲或不利于后續的點云處理和分析。函數通過比較每個點與傳感器之間的距離,移除那些距離小于設定閾值 minimumRange 的點。 計算…

網絡連接之隊頭阻塞!!!

一、什么是隊頭阻塞 隊頭阻塞&#xff0c;在網絡模型中簡單理解就是&#xff0c;對于隊列型的請求模型&#xff0c;如HTTP的請求-響應模型、TCP的ACK確認機制&#xff0c;都依賴得到一個具體的響應包&#xff0c;如果收不到這個響應包&#xff0c;那下一個請求就不能發&#x…

4、音視頻封裝格式---FLV

FLV FLV是一種容器封裝格式&#xff0c;是由Adobe公司發布和維護的&#xff0c;用于將視頻編碼流與音頻編碼流進行封裝。對于任意一種封裝格式&#xff0c;都有其頭部區域與數據區域&#xff0c;在FLV中&#xff0c;稱之為FLV Header與Body。 對于FLV Header&#xff0c;一個FL…

python自動移除excel文件密碼(升級v2版本)

歡迎查看第一版 https://blog.csdn.net/weixin_45631815/article/details/140013476?spm1001.2014.3001.5502 一功能改進 此版本主要改進功能有以下: 直接可以調用函數實現可以嘗試多個密碼沒有加密的文件進行保存,可以按實際業務進行改進.思路來源:java 面向對象設計模式.…

煤礦安全大模型:微調internlm2模型實現針對煤礦事故和煤礦安全知識的智能問答

煤礦安全大模型————礦途智護者 使用煤礦歷史事故案例,事故處理報告、安全規程規章制度、技術文檔、煤礦從業人員入職考試題庫等數據,微調internlm2模型實現針對煤礦事故和煤礦安全知識的智能問答。 本項目簡介: 近年來,國家對煤礦安全生產的重視程度不斷提升。為了確…

SpringBoot+mail 輕松實現各類郵件自動推送

一、簡介 在實際的項目開發過程中&#xff0c;經常需要用到郵件通知功能。例如&#xff0c;通過郵箱注冊&#xff0c;郵箱找回密碼&#xff0c;郵箱推送報表等等&#xff0c;實際的應用場景非常的多。 早期的時候&#xff0c;為了能實現郵件的自動發送功能&#xff0c;通常會…

前端期末1111

前端期末 超文本標記語言&#xff08;英語&#xff1a;HyperText Markup Language&#xff0c;簡稱&#xff1a;HTML&#xff09; body&#xff1a;在網頁文檔中&#xff0c;所有文本&#xff0c;圖像&#xff0c;音頻和視頻等代碼只能放在標簽內才能呈現給用戶。 HTML中的標…

【STM32入門教學】——串口、定時器與參考資料

機器人工程系列文章目錄 這里羅列了系列文章鏈接 概念總述 STM入門教學 還沒寫完組里急用 文章目錄 機器人工程系列文章目錄概念總述STM入門教學 前言串口串口的概念cubemxkeil5實物實驗關于cubemx生成邏輯printf升級usart.cmain.hretarget.c 定時器定時器的概念cubemxkeil5…

帶電池監控功能的恒流直流負載組

EAK的交流和直流工業電池負載組測試儀對于測試和驗證關鍵電力系統的能力至關重要&#xff0c;旨在實現最佳精度。作為一家客戶至上的公司&#xff0c;我們繼續盡我們所能應對供應鏈挑戰&#xff0c;以提供出色的交貨時間&#xff0c;大約是行業其他公司的一半。 交流負載組 我…

時鐘切換的代碼

目錄 描述 輸入描述&#xff1a; 輸出描述&#xff1a; 參考代碼 描述 題目描述&#xff1a; 存在兩個同步的倍頻時鐘clk0 clk1,已知clk0是clk1的二倍頻&#xff0c;現在要設計一個切換電路&#xff0c;sel選擇時候進行切換&#xff0c;要求沒有毛刺。 信號示意圖&…

學習springMVC

第四章 Spring MVC 第一節 Spring MVC 簡介 1. Spring MVC SpringMVC是一個Java 開源框架&#xff0c; 是Spring Framework生態中的一個獨立模塊&#xff0c;它基于 Spring 實現了Web MVC&#xff08;數據、業務與展現&#xff09;設計模式的請求驅動類型的輕量級Web框架&am…

車云匯的元宇宙之旅

在汽車行業持續迎來數字化和科技革新的今天&#xff0c;車云匯作為一個領先的汽車服務平臺&#xff0c;正通過探索元宇宙這一新興概念&#xff0c;將傳統服務與虛擬現實技術相結合&#xff0c;為車主提供全新的互動體驗和服務模式。這一創新不僅有望改變汽車行業的服務面貌&…

匿名內部類在Java編程中的應用與限制

匿名內部類在Java編程中的應用與限制 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 匿名內部類在Java編程中的應用與限制 1. 什么是匿名內部類&#xff1f;…

什么叫創世區塊、創世區塊有什么用、為什么需要創世區塊

創世區塊&#xff08;Genesis Block&#xff09;是任何區塊鏈技術中的第一個區塊&#xff0c;它是區塊鏈的起點&#xff0c;標志著該區塊鏈的誕生。在創世區塊之前沒有任何區塊存在&#xff0c;因此它沒有前一個區塊的哈希值&#xff0c;通常這個位置會被設置為零或者一個預定義…

vue3源碼(六)渲染原理-runtime-dom

1、從入口文件看實現 項目入口文件 import { createApp } from vue import ./style.css import App from ./App.vuecreateApp(App).mount(#app)文件位置core\packages\runtime-dom\src\index.ts 保證了render的唯一性 // // rendererOptions 是patchProp 和nodeOps的合集&a…