深入学习C语言:探索文件操作技巧
这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战
文件操作
文件操作在实际工作中,用到的并不多。但没有它C语言又不完整。所以本次我们研究一下C语言的文件操作。
文件的定义
将数据存储到外存(写入文件),每次程序结束后可以避免数据丢失,可以在程序运行时将数据加载到内存中,这是文件存在的意义。
在程序设计中,从文件功能的角度分类,一般谈到的文件有两种:程序文件和数据文件。
-
程序文件:跟程序有关的文件,如源文件
.c
,编译产生的目标文件.obj
,可执行程序.exe
等。 -
数据文件:配合程序进行读写操作的,存储程序运行时所读写数据的文件,如
.txt
。
注意,数据文件和程序文件之间的操作,被称为读和写。以程序为对象,向外修改数据或输出内容被称为写入,从数据文件到程序文件的获取数据被称为读取。而写即为输出,读被称为输入。
和之前不同的是,数据所输入输出的对象从终端变成了文件。如printf
,scanf
分别是将数据输出到屏幕和从键盘输入数据。 如今我们可以将屏幕和键盘换成文件,对文件进行输入和输出。
而本章所讨论的文件就是数据文件。
文件名
每个文件有且仅有一个唯一的文件标识,用于描述文件。文件标识包含3个部分:文件路径+文件名主干+文件后缀。
例如:D:\code\data.txt
。 方便起见,文件标识通常成为文件名。如图:
文件类型
根据数据的组织形式,数据文件被分为两种:文本文件或者二进制文件。
- 二进制文件:数据在内存中以二进制的形式存储,再直接输出到外存,就是二进制文件。
- 文本文件:数据转换成ASCII码的形式再存储到外存中,就是文本文件。
如上图所示,
test.c
打开后可以看懂,则是文本文件,*.exe
打开后显示乱码,则是二进制文件。
数据的存储
数据在内存中存储时,字符一律以ASCII码的形式存储,而数值可以以ASCII码的形式也可以以二进制的形式存储。
例有整数10000,若以ASCII码的形式存储,则5个字符共需5个字节。若以二进制的形式存储,则转化成补码,整型数据共需4个字节。
使用下列代码,将10000以二进制的形式存入文件
data.txt
中。
int main() {
FILE* pf = fopen("data.txt", "wb");
if (pf == NULL) {
perror("fopen");
return -1;
}
int a = 10000;
fwrite(&a, 4, 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
我们用二进制编辑器查看以二进制形式写入文件的10000,可以看到如下现象:可以按照如下推理得出答案。
//1.
00000000 00000000 00100111 00010000 - 10000原码
//2.c
00010000 00100111 00000000 00000000 - 小端存储
//3.
1 0 2 7 0 0 0 0 - 转化成十六进制
10 27 00 00
文件缓冲区
C标准规定采用**“缓冲文件系统”处理数据文件,缓冲文件系统即是系统自动为程序所使用每一个文件开辟一块“文件缓冲区”**。
- 从内存向外存输出数据会先经过输出缓冲区,装满输出缓冲区后才一起输送到外存。同样,
- 从外存向内存输入数据会先经过输入缓冲区,装满输入缓冲区后再一起输入到内存。
缓冲区的大小由编译系统决定,具体多少算“满”,C语言阶段不深入研究。
二者之间传递数据的操作是由程序调起操作系提供的输入输出的接口完成的。目的是使之不会频繁地传输打断操作系统。
文件信息区
缓冲文件系统中,有个关键的概念叫“文件类型指针”,简称“文件指针”。
当程序操作一个文件的时候,都在内存中开辟了一个与该文件相对应的文件信息区,用于存放文件的相关信息(如文件名称,状态,位置等)。这些信息都是一个结构体的成员,该结构体类型由系统声明,取名为"FILE"。
每一个文件被操作时,都会先创建好一个文件信息区,所谓文件信息区其实就是一个被封装好的结构体类型所创建的变量,该变量与所属文件强关联。操作文件其实就是操作文件信息区,打开文件其实返回了文件信息区的地址。如图:
从内存读取方式中也可窥探一番,内存中数据也是一级一级读取的,先将内存中的数据提至缓存区,再放到寄存器中。读取文件也是这样的逻辑,不然直接读取整个文件,加载慢占存大也容易出错。
vs2013
中仍可以看到文件信息区的结构体封装内容,可以看出都是文件的相关信息。文件信息区就是FILE
类型的结构体变量。
文件指针
这些变量都是由系统封装好自动创建的,不必关注细节。一般都是通过FILE*
的指针来维护该FILE
结构体变量,这就是文件指针。
FILE* pf;//指向文件信息区的指针
通过FILE
类型的结构体指针变量pf
,可指向某个文件信息区从而操作该文件。如图:
文件的开关操作
想要通过文件指针进行文件操作,必须先打开文件,使用结束后关闭文件。操作文件的步骤分为:1. 打开文件 2. 读写文件 3. 关闭文件。
C语言标准规定,使用fopen
和fclose
来打开和关闭文件。
文件的打开 fopen
函数声明
FILE* fopen (const char* filename, const char* mode);
Return Value
This function returns a pointer to the open file. A null pointer value indicates an error.
Parameters
1. filename - Filename
2. mode - Type of access permitted
Remarks
The fopen function opens the file specified by filename.
fopen
函数以mode
的方式打开名为filename
的文件,并返回文件信息区的起始地址。
函数用法
- 打开文件以读还是写的方式由
mode
决定。打开方式如下:
模式 | 方式 | 含义 | 备注 |
---|---|---|---|
"r" | 只读 | 输入数据,打开已存在的文本文件 | 文件不存在,则调用失败 |
"w" | 只写 | 输出数据,“新建”一个文本文件 | 文件已存在,则销毁内容 |
"a" | 追加 | 输出数据,向文本文件末尾添加数据 | 文件不存在,则创建文件 |
"rb" | 只读 | 输入数据,打开已存在的二进制文件 | 文件不存在,则调用失败 |
"wb" | 只写 | 输出数据,“新建”一个二进制文件 | 文件已存在,则销毁内容 |
"ab" | 追加 | 输出数据,向二进制文件末尾添加数据 | 文件不存在,则创建文件 |
"r+" | 读写 | 兼具输入输出,打开已存在的文本文件 | 文件不存在,则调用失败 |
"w+" | 读写 | 兼具输入输出,“新建”一个文本文件 | 文件已存在,则销毁内容 |
"a+" | 读加 | 兼具输入输出,向文本文件末尾添加数据 | 文件不存在,则创建文件 |
... |
- 文件名
filename
可采用相对路径即解决方案目录下文件夹和绝对路径即文件路径+文件名主干+后缀。
//打开文件
//1. 绝对路径
FILE* pf = fopen("C:\\Users\\w3395\\Desktop\\data.txt", "w");
//2. 相对路径
FILE* pf = fopen("data.txt", "w");
文件的关闭 fclose
函数声明
int fclose (FILE* stream);
Return Value
fclose returns 0 if the stream is successfully closed.
Parameter
1. stream - Pointer to FILE structure
Remarks
The fclose function closes stream.
fclose
函数关闭对文件信息区的输入输出流。
函数用法
-
fclose
仅关闭了关于文件的输入输出流,不会将文件指针置空。为防止出现野指针,需置空文件指针。
int main() {
//打开文件
FILE* pf = fopen("data.txt", "w");
//打开失败
if (pf == NULL) {
perror("fopen");
return -1;
}
//操作文件
//...
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
文件的读写操作
流的定义
“流是磁盘或其它外围设备中存储的数据的源点或终点” —— 《C语言程序设计》
流主要是指一种逻辑上的概念,产生数据的叫输入流,消耗数据的叫输出流。至于产生和消耗,因设备不同而有所差异,但C语言中对它们一视同仁,以“流”代之。
将字符放入文件中,或打印到屏幕上,这里的文件和屏幕就是外部设备。如屏幕、网络、文件,硬盘都是外部设备。不同设备的读写方式肯定不一样,为方便起见,故抽象出“流”的概念,以一个“流”字来概括它们的特征。故可把流看作是一种数据的载体,通过它可以实现数据交换和传输,传递数据的方式由“流”决定。我们仅需将数据放入“流”当中即可。
程序与数据的交互是以“流”的形式进行的。对象间进行数据的交换时总是先将数据转换为某种形式的流,再通过流的传输,到达目标对象后再将流转换为对象数据。C语言中文件读写时,都会先进行“打开文件”操作,这个操作就是在打开数据流,而“关闭文件”操作就是关闭数据流。
当我们使用
printf
,scanf
时即是通过标准输入输出流在屏幕键盘和程序之间传递的。一般程序中会有三种流:标准输出流stdout
,标准输入流stdin
,标准错误流stderr
,三种流都是FILE*
的指针。
文件的顺序读写
下列是成对的,顺序读取和写入操作函数,分别适用于不同类型的数据。所有输出流包括文件输出流和标准输出流。
函数名 | 功能 | 适用范围 |
---|---|---|
fgetc |
字符输入函数 | 所有输入流 |
fputc |
字符输出函数 | 所有输出流 |
fgets |
文本行输入函数 | 所有输入流 |
fputs |
文本行输出函数 | 所有输出流 |
fscanf |
格式化输入函数 | 所有输入流 |
fprintf |
格式化输出函数 | 所有输出流 |
fread |
二进制输入 | 文件 |
fwrite |
二进制输出 | 文件 |
字符输入输出 fputc
&fgetc
函数声明
int fputc (int c, FILE* stream);
Return Value
This function returns the character written.
Parameters
1. c - Character to be written
2. stream - Pointer to FILE structure
Remarks
This function writes the single character c to a file at the position pointed by the associated file position pointer (if defined) and advances the pointer appropriately(适当).
int fgetc (FILE* stream);
Return Value
fgetc return the character read as an int or return EOF to indicate an error or end of file.
Parameter
stream - Pointer to FILE structure
Remarks
This function reads a single character from the current position of a file; The function then increments(递增) the associated file pointer (if defined) to point to the next character.
fputc
将字符c
放到文件指针stream
所指向的文件中。
fgetc
返回文件指针所指向的字符。
函数用法
-
fputc
每写入一个字符文件指针就向后移动一个字符的位置。fgetc
每读取一个字符文件指针就向后移动一个字符的位置。 -
fputc
适用于所有输出流,可以输出到任意设备上。fgetc
同样适用于所有输入流,可以从任意设备上读取数据。
int main() {
FILE* pf = fopen("data.txt", "w");
if (pf == NULL) {
perror("fopen");
return -1;
}
fputc('a', pf);
fputc('b', pf);
fputc('c', pf);
fclose(pf);
pf = NULL;
return 0;
}
int main() {
FILE* pf = fopen("data.txt", "r");
if (pf == NULL) {
perror("fopen");
return -1;
}
int ch = fgetc(pf);
printf("%c ", ch);
ch = fgetc(pf);
printf("%c ", ch);
ch = fgetc(pf);
printf("%c ", ch);
fclose(pf);
pf = NULL;
return 0;
}
//标准输出流
fputc('b', stdout);
fputc('i', stdout);
fputc('t', stdout);
//标准输入流
printf("%c\n", fgetc(stdin));
printf("%c\n", fgetc(stdin));
printf("%c\n", fgetc(stdin));
字符串输入输出 fputs
&fgets
函数声明
int fputs (const char* string, FILE* stream);
Return Value
This function returns a nonnegative(非负) value if it is successful. On an error, fputs returns EOF.
Parameters
1. string - Output string
2. stream - Pointer to FILE structure
Remarks
This function copies string to the output stream at the current position.
char* fgets (char* string, int n, FILE* stream);
Return Value
This function returns string. NULL is returned to indicate an error or an end-of-file condition.
Parameters
1. string - Storage location for data
2. n - Maximum number of characters to read
3. stream - Pointer to FILE structure
Remarks
The fgets function reads a string from the input stream argument and stores it in string. fgets reads characters from the current stream position to and including the first newline character, to the end of the stream, or until the number of characters read is equal to n – 1, whichever comes first. The result stored in string is appended with a null character. The newline character, if read, is included in the string.
fputc
将字符串string
放到文件指针stream
所指向的文件中。
fgets
将stream
文件中指向的字符串的前n-1
个字符放入string
中,并以返回值的形式返回。
函数用法
-
fputs
一次写入一行,若需换行可以加上\n
,文件指针移动到末尾。 -
fgets
每次只读取规定字符数 个字符最后第 个字符为\0
作为字符串结束标志。
-
fputs
适用于所有输出流,可以输出到任意设备上。fgets
同样适用于所有输入流,可以从任意设备上读取数据。
int main() {
FILE* pf = fopen("data.txt", "w");
if (pf == NULL) {
perror("fopen");
return -1;
}
fputs("hello world!\n", pf);
fputs("hello bit!\n", pf);
fclose(pf);
pf = NULL;
return 0;
}
int main() {
FILE* pf = fopen("data.txt", "r");
if (pf == NULL) {
perror("fopen");
return -1;
}
char arr[20] = { 0 };
fgets(arr, 5, pf);
printf("%s\n", arr);
fgets(arr, 5, pf);
printf("%s\n", arr);
fclose(pf);
pf = NULL;
return 0;
}
格式化输入输出 fprintf
&pscanf
函数声明
int fprintf (FILE* stream, const char* format [, argument ]...);
Return Value
fprintf returns the number of bytes written. This function returns a negative value instead when an output error occurs.
Parameters
1. stream - Pointer to FILE structure
2. format - Format-control string
3. argument - Optional arguments
Remarks
fprintf formats(格式化) and prints all characters and values to the output stream. Each argument(参数) is converted(转换) and output according to the corresponding format specification(规范). For fprintf, the format argument has the same syntax(语法) that it has in printf.
int fscanf (FILE* stream, const char* format [, argument ]...);
Return Value
This function returns the number of fields(字段数) successfully converted(转化) and assigned(分配);
Parameters
1. stream - Pointer to FILE structure
2. format - Format-control string
3. argument - Optional arguments
Remarks
The fscanf function reads data from the current position of stream into the locations given by argument (if any). It has the same form and function as the format argument for scanf;
fprintf
,fscanf
是以格式化的形式,例如:"%d,%f",a,f
,输出输入到所有输入输出流。
函数用法
-
fprintf
,fscanf
和 printf,scnaf 的参数差别仅是前面带有文件指针pf
,故写好 printf,scanf 的形式再在参数列表最前添上文件指针pf
。如:
struct S {
int a;
char c;
double d;
};
int main() {
FILE* pf = fopen("data.txt", "w");
if (pf == NULL) {
perror("fopen");
return -1;
}
struct S s = { 100,'w',3.14 };
fprintf(pf, "%d %c %lf", s.a, s.c ,s.d);
return 0;
}
int main() {
FILE* pf = fopen("data.txt", "r");
if (pf == NULL) {
perror("fopen");
return -1;
}
struct S s = { 0 };
fscanf(pf, "%d %c %lf", &s.a, &s.c, &s.d);
printf("%d %c %lf", s.a, s.c, s.d);
return 0;
}
-
fprintf
适用于所有输出流,可以输出到任意设备上。fscanf
同样适用于所有输入流,可以从任意设备上读取数据。
以上有适用于单个字符的,适用于字符串的以及适用于任意格式的字符,字符串,格式化输入输出函数。但都是文本形式的输入输出函数,接下来的是以二进制的形式的输入输出函数。
二进制输入输出 fwrite
&fread
函数声明
size_t fwrite (const void* buffer, size_t size, size_t count, FILE* stream);
Return Value
fwrite returns the number of full items actually written.
Parameters
1. buffer - Pointer to data to be written(指向待写数据的指针)
2. size - Item size in bytes(元素宽度)
3. count - Number of items to be written(元素个数)
4. stream - Pointer to FILE structure(文件指针)
Remarks
The fwrite function writes up to count items, of size length each, from buffer to the output stream. The file pointer associated with stream (if there is one) is incremented by the number of bytes actually written.
size_t fread (void* buffer, size_t size, size_t count, FILE* stream);
Return Value
fread returns the number of full items actually read, which may be less than count if an error occurs or if the end of the file is encountered before reaching count.
Parameters
1. buffer - Storage location for data
2. size - Item size in bytes
3. count - Maximum number of items to be read
4. stream - Pointer to FILE structure
Remarks
The fread function reads up to count items of size bytes from the input stream and stores them in buffer. The file pointer associated with stream (if there is one) is increased by the number of bytes actually read.
函数用法
-
fwrite
把从buffer
位置的count
个大小为size
的元素以二进制的形式写入文件stream
中。
-
fread
把从文件stream
的中count
个大小为size
的元素以二进制的形式读取到buffer
中。
struct S {
int a;
char c[20];
double d;
};
int main() {
FILE* pf = fopen("data.txt", "wb");
if (pf == NULL) {
perror("fopen");
return -1;
}
struct S s = { 100,"yyx",3.14 };
fwrite(&s, sizeof(s), 1, pf);
return 0;
}
int main() {
FILE* pf = fopen("data.txt", "rb");
if (pf == NULL) {
perror("fopen");
return -1;
}
struct S s = { 0 };
fread(&s, sizeof(s), 1, pf);
printf("%d %s %lf", s.a, s.c, s.d);
return 0;
}
输入输出函数的对比
//1.
scanf/fscanf/sscanf
//2.
printf/fprintf/sprintf
函数名 | 内容 | 备注 |
---|---|---|
scanf |
从标准输入流(键盘)读取格式化的数据 | 省略standard |
fscanf |
从所有输入流读取读取格式化数据 | f:file |
sscanf |
从字符串中读取格式化的数据 | s:string |
printf |
将格式化的数据输出到标准输出流(屏幕)上 | 省略standard |
fprintf |
将格式化数据输出到所有输出流上 | f:file |
sprintf |
将格式化的数据输出到字符串中 | s:string |
int main() {
//sprintf
struct S s = { 100,"yyx",3.14 };
char arr[20] = { 0 };
sprintf(arr, "%d%s%lf", s.a, s.c, s.d);
printf("%s\n", arr);
//sscanf
sscanf(arr, "%d %s %lf", &s.a, s.c, &s.d);
printf("%d %s %lf", s.a, s.c, s.d);
return 0;
}
sprintf
把格式化的数据输出到字符串中,sscanf
把字符串中的数据输入到程序(格式化形式读取)。
文件的随机读写
随机读写,即随意改变文件指针的位置进行自定义位置的读写。
更改文件指针 fseek
函数声明
int fseek (FILE* stream, long offset, int origin);
Return Value
If successful, fseek returns 0. Otherwise, it returns a nonzero value.
Parameters
1. stream - Pointer to FILE structure
2. offset - Number of bytes from origin
3. origin - Initial position
Remarks
The fseek function moves the file pointer (if any) associated with stream to a new location that is offset bytes from origin.
fseek
通过文件指针距起始位置的偏移量来完成对文件指针的重定位。
函数用法
- 起始位置
origin
可以传三种值:SEEK_SET
,SEEK_END
,SEEK_CUR
,分别对应文件起始,文件末尾,文件当前位置。
- 文件指针偏移量即两个指针相减的结果。输入输出函数也会影响文件指针当前的位置。
'f'
相对于起始位置SEEK_SET
的偏移量为4,相对于文件末尾SEEK_END
的偏移量为-8。
-
fseek
函数仅是重定位文件指针,不包含任何的输入输出语句。
int main()
{
FILE* pf = fopen("C:\\Users\\w3395\\Desktop\\data.txt", "r");
if (pf == NULL) {
perror("fopen");
return -1;
}
//读取字符
printf("%c", fgetc(pf));//y
fseek(pf, 1, SEEK_SET);
printf("%c", fgetc(pf));//o
fseek(pf, 2, SEEK_SET);
printf("%c", fgetc(pf));//u
fseek(pf, 3, SEEK_SET);
printf("%c", fgetc(pf));//r
fseek(pf, -2, SEEK_CUR);
printf("%c", fgetc(pf));//u
fseek(pf, -2, SEEK_CUR);
printf("%c", fgetc(pf));//o
fseek(pf, -2, SEEK_CUR);
printf("%c", fgetc(pf));//y
fclose(pf);
pf = NULL;
return 0;
}
定位文件指针 ftell
函数声明
long ftell (FILE* stream);
Return Value
ftell returns the current file position.
Parameter
stream - Target FILE structure
Remarks
The ftell function gets the current position of the file pointer (if any) expressed as an offset relative to the beginning of the stream.
ftell
以距起始位置的偏移量的形式返回当前文件指针的位置。
函数用法
int main()
{
FILE* pf = fopen("C:\\Users\\w3395\\Desktop\\data.txt", "r");
if (pf == NULL) {
perror("fopen");
return -1;
}
fseek(pf, 3, SEEK_SET);
int ret = ftell(pf);
printf("%d\n", ret);
return 0;
}
重置文件指针 rewind
函数声明
void rewind (FILE* stream);
Return Value
None
Parameter
stream - Pointer to FILE structure
Remarks
The rewind function repositions(重置) the file pointer associated with stream to the beginning of the file.
函数用法
-
rewind
将文件指针恢复初始状态。
文件结束的判断
输入函数返回值的判断
类似于oj
题中,多次输入的方法,利用scanf
的返回值进行判断:
while (scanf("%d", &n) != EOF)} {
;
}
由于在
oj
题中输入由系统控制(类似于读取文件),当读取结束时会返回EOF,所以在循环判断部分对scanf
的返回值进行判断,可以达到多次读入的效果。
文件输入函数具有同样的特点,也可以利用其返回值进行判断,以达到循环读入的目的。
输入函数 | 利用返回值判断 |
---|---|
fgetc |
以整型的形式返回读到的字符,遇到错误或文件结束时返回EOF |
fgets |
返回读到的字符串,遇到错误或文件结束时返回NULL |
fscanf |
返回成功读到并转化的字段数,当小于规定字段数时读取失败,没有字段时返回0 |
fread |
返回实际读到的元素个数,若小于参数count则无可再读。 |
具体实现如下列代码:
//fgetc
int ch = 0;
while ((ch = fgetc(pf)) != EOF) {
printf("%c ", ch);
}
//fgets
char arr[2][20] = { 0 };
while ((fgets(arr, 3, pf)) != NULL) {
printf("%s\n", arr);
}
//fscanf
int ch = 0;
while (fscanf(pf, "%c", &ch) == 1) {
printf("%c\n", ch);
}
//fread
int ch = 0;
while (fread(&ch, 1, 1, pf) == 1) {
printf("%c\n", ch);
}
判断文件结束 feof
feof
不是用于判断文件是否读取结束的。而是当文件读取结束时,用于判断结束的原因是遇到错误还是到达文件末尾的。
函数声明
Return Value
feof returns a nonzero value after the first read operation that attempts to read past the end of the file. It returns 0 if the current position is not end of file. There is no error return.
函数用法
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL) {
perror("fopen");
return -1;
}
int ch = 0;
while ((ch = fgetc(pf)) != EOF) {
printf("%c ", ch);
}
if (feof(pf)) {
printf("\n%s\n", "end of file reached successfully");
}
if (ferror(pf)) {
printf("\n%s\n", "unknowed error");
}
fclose(pf);
pf = NULL;
return 0;
}
-
feof
:是当文件结束时,判断是否是遇到文件末尾而结束的。
遇到文件末尾而结束时,返回一个非零值,其他情况返回0。
-
ferror
:是当文件结束时,判断是否是遇到错误而结束的。
遇到错误而结束时,返回一个非零值,其他情况返回0。
上一篇: gcc如何指定编译头文件的位置
下一篇: C语言文件操作
推荐阅读
-
深入剖析C语言中的FILE文件操作
-
深入剖析C语言文件操作
-
文件操作学习指南:探索C语言中的文件处理
-
深入剖析C语言文件操作
-
探索C语言中的文件操作
-
深入学习C语言:探索文件操作技巧
-
go语言Socket编程-Socket编程 什么是Socket Socket,英文含义是插座、插孔,一般称之为套接字,用于描述IP地址和端口。可以实现不同程序间的数据通信。 Socket起源于Unix,而Unix基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用:Socket,该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。 套接字的内核实现较为复杂,不宜在学习初期深入学习,了解到如下结构足矣。 套接字通讯原理示意 在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。 常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 网络应用程序设计模式 C/S模式 传统的网络应用设计模式,客户机(client)/服务器(server)模式。需要在通讯两端各自部署客户机和服务器来完成数据通信。 B/S模式 浏览器(Browser)/服务器(Server)模式。只需在一端部署服务器,而另外一端使用每台PC都默认配置的浏览器即可完成数据的传输。 优缺点 对于C/S模式来说,其优点明显。客户端位于目标主机上可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。且,一般来说客户端和服务器程序由一个开发团队创作,所以他们之间所采用的协议相对灵活。可以在标准协议的基础上根据需求裁剪及定制。例如,腾讯所采用的通信协议,即为ftp协议的修改剪裁版。 因此,传统的网络应用程序及较大型的网络应用程序都首选C/S模式进行开发。如,知名的网络游戏魔兽世界。3D画面,数据量庞大,使用C/S模式可以提前在本地进行大量数据的缓存处理,从而提高观感。 C/S模式的缺点也较突出。由于客户端和服务器都需要有一个开发团队来完成开发。工作量将成倍提升,开发周期较长。另外,从用户角度出发,需要将客户端安插至用户主机上,对用户主机的安全性构成威胁。这也是很多用户不愿使用C/S模式应用程序的重要原因。 B/S模式相比C/S模式而言,由于它没有独立的客户端,使用标准浏览器作为客户端,其工作开发量较小。只需开发服务器端即可。另外由于其采用浏览器显示数据,因此移植性非常好,不受平台限制。如早期的偷菜游戏,在各个平台上都可以完美运行。 B/S模式的缺点也较明显。由于使用第三方浏览器,因此网络应用支持受限。另外,没有客户端放到对方主机上,缓存数据不尽如人意,从而传输数据量受到限制。应用的观感大打折扣。第三,必须与浏览器一样,采用标准http协议进行通信,协议选择不灵活。 因此在开发过程中,模式的选择由上述各自的特点决定。根据实际需求选择应用程序设计模式。 简单的C/S模型通信 Server端:Listen函数 func Listen(network, address string) (Listener, error) network:选用的协议:TCP、UDP, 如:“tcp”或 “udp” address:IP地址+端口号, 如:“127.0.0.1:8000”或 “:8000” Listener 接口: type Listener interface { Accept (Conn, error) Close error Addr Addr } Conn 接口: type Conn interface { Read(b byte) (n int, err error) Write(b byte) (n int, err error) Close error LocalAddr Addr RemoteAddr Addr SetDeadline(t time.Time) error SetReadDeadline(t time.Time) error SetWriteDeadline(t time.Time) error } 参看 [<u>https://studygolang.com/pkgdoc</u>](https://studygolang.com/pkgdoc) 中文帮助文档中的demo: 示例代码:TCP服务器.go package main import ( "net" "fmt" ) func main { // 创建监听 listener, err:= net.Listen("tcp", ":8000") if err != nil { fmt.Println("listen err:", err) return } defer listener.Close // 主协程结束时,关闭listener fmt.Println("服务器等待客户端建立连接...") // 等待客户端连接请求 conn, err := listener.Accept if err != nil { fmt.Println("accept err:", err) return } defer conn.Close // 使用结束,断开与客户端链接 fmt.Println("客户端与服务器连接建立成功...") // 接收客户端数据 buf := make(byte, 1024) // 创建1024大小的缓冲区,用于read n, err := conn.Read(buf) if err != nil { fmt.Println("read err:", err) return } fmt.Println("服务器读到:", string(buf[:n])) // 读多少,打印多少。 }
-
包婷婷 (201550484)作业一 统计软件简介与数据操作-SPSS(Statistical Product and Service Solutions),"统计产品与服务解决方案"软件。最初软件全称为"(SolutionsStatistical Package for the Social Sciences),但是随着SPSS产品服务领域的扩大和服务深度的增加,SPSS公司已于2000年正式将英文全称更改为"统计产品与服务解决方案",标志着SPSS的战略方向正在做出重大调整。为IBM公司推出的一系列用于统计学分析运算、数据挖掘、预测分析和决策支持任务的软件产品及相关服务的总称SPSS,有Windows和Mac OS X等版本。 1984年SPSS总部首先推出了世界上第一个统计分析软件微机版本SPSS/PC+,开创了SPSS微机系列产品的开发方向,极大地扩充了它的应用范围,并使其能很快地应用于自然科学、技术科学、社会科学的各个领域。世界上许多有影响的报刊杂志纷纷就SPSS的自动统计绘图、数据的深入分析、使用方便、功能齐全等方面给予了高度的评价。 R统计软件介绍 R是一套完整的数据处理、计算和制图软件系统。其功能包括:数据存储和处理系统;数组运算工具(其向量、矩阵运算方面功能尤其强大);完整连贯的统计分析工具;优秀的统计制图功能;简便而强大的编程语言:可操纵数据的输入和输出,可实现分支、循环,用户可自定义功能。 与其说R是一种统计软件,还不如说R是一种数学计算的环境,因为R并不是仅仅提供若干统计程序、使用者只需指定数据库和若干参数便可进行一个统计分析。R的思想是:它可以提供一些集成的统计工具,但更大量的是它提供各种数学计算、统计计算的函数,从而使使用者能灵活机动的进行数据分析,甚至创造出符合需要的新的统计计算方法。 该语言的语法表面上类似 C,但在语义上是函数设计语言(functional programming language)的变种并且和Lisp 以及 APL有很强的兼容性。特别的是,它允许在"语言上计算"(computing on the language)。这使得它可以把表达式作为函数的输入参数,而这种做法对统计模拟和绘图非常有用。 R是一个免费的*软件,它有UNIX、LINUX、MacOS和WINDOWS版本,都是可以免费下载和使用的。在R主页那儿可以下载到R的安装程序、各种外挂程序和文档。在R的安装程序中只包含了8个基础模块,其他外在模块可以通过CRAN获得。 二、R语言 R是用于统计分析、绘图的语言和操作环境。R是属于GNU系统的一个*、免费、源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具。 R作为一种统计分析软件,是集统计分析与图形显示于一体的。它可以运行于UNIX,Windows和Macintosh的操作系统上,而且嵌入了一个非常方便实用的帮助系统,相比于其他统计分析软件,R还有以下特点: 1.R是*软件。这意味着它是完全免费,开放源代码的。可以在它的网站及其镜像中下载任何有关的安装程序、源代码、程序包及其源代码、文档资料。标准的安装文件身自身就带有许多模块和内嵌统计函数,安装好后可以直接实现许多常用的统计功能。[2] 2.R是一种可编程的语言。作为一个开放的统计编程环境,语法通俗易懂,很容易学会和掌握语言的语法。而且学会之后,我们可以编制自己的函数来扩展现有的语言。这也就是为什么它的更新速度比一般统计软件,如,SPSS,SAS等快得多。大多数最新的统计方法和技术都可以在R中直接得到。[2] 3. 所有R的函数和数据集是保存在程序包里面的。只有当一个包被载入时,它的内容才可以被访问。一些常用、基本的程序包已经被收入了标准安装文件中,随着新的统计分析方法的出现,标准安装文件中所包含的程序包也随着版本的更新而不断变化。在另外版安装文件中,已经包含的程序包有:base一R的基础模块、mle一极大似然估计模块、ts一时间序列分析模块、mva一多元统计分析模块、survival一生存分析模块等等.[2] 4.R具有很强的互动性。除了图形输出是在另外的窗口处,它的输入输出窗口都是在同一个窗口进行的,输入语法中如果出现错误会马上在窗口口中得到提示,对以前输入过的命令有记忆功能,可以随时再现、编辑修改以满足用户的需要。输出的图形可以直接保存为JPG,BMP,PNG等图片格式,还可以直接保存为PDF文件。另外,和其他编程语言和数据库之间有很好的接口。[2] 5.如果加入R的帮助邮件列表一,每天都可能会收到几十份关于R的邮件资讯。可以和全球一流的统计计算方面的专家讨论各种问题,可以说是全世界最大、最前沿的统计学家思维的聚集地.[2] R是基于S语言的一个GNU项目,所以也可以当作S语言的一种实现,通常用S语言编写的代码都可以不作修改的在R环境下运行。 R的语法是来自Scheme。R的使用与S-PLUS有很多类似之处,这两种语言有一定的兼容性。S-PLUS的使用手册,只要稍加修改就可作为R的使用手册。所以有人说:R,是S-PLUS的一个“克隆”。 但是请不要忘了:R是免费的(R is free)。R语言源代码托管在github,具体地址可以看参考资料。[3] 。 R语言的下载可以通过CRAN的镜像来查找。 R语言有域名为.cn的下载地址,有六个,其中两个由Datagurn,由 中国科学技术大学提供的。R语言Windows版,其中由两个下载地点是Datagurn和 USTC提供的。 三、stata Stata 是一套提供其使用者数据分析、数据管理以及绘制专业图表的完整及整合性统计软件。它提供许许多多功能,包含线性混合模型、均衡重复反复及多项式普罗比模式。用Stata绘制的统计图形相当精美。 新版本的STATA采用最具亲和力的窗口接口,使用者自行建立程序时,软件能提供具有直接命令式的语法。Stata提供完整的使用手册,包含统计样本建立、解释、模型与语法、文献等超过一万余页的出版品。 除此之外,Stata软件可以透过网络实时更新每天的最新功能,更可以得知世界各地的使用者对于STATA公司提出的问题与解决之道。使用者也可以透过Stata. Journal获得许许多多的相关讯息以及书籍介绍等。另外一个获取庞大资源的管道就是Statalist,它是一个独立的listserver,每月交替提供使用者超过1000个讯息以及50个程序。 四、PYTHON
-
41 个下载免费 3D 模型的最佳网站-使用说明:使用权限可能因型号而异。因此,在下载文件之前,请仔细检查每个下载页面上的许可证和使用权限。 17. Clara.io Clara.io 是一个创建 3D 内容的全球平台,也是一个培养新 3D 艺术家的社区。Clara.io 提供+100,000个免费的3D模型,包括OBJ,Blend,STL,FBX,DAE,Babylon.JS,Three.JS格式,用于 Clara.io,Unity 3D,Blender,Sketchup,Cinema 4D,3DS Max和Maya。 使用说明:免费,标准和专业帐户仅供个人使用,如果您需要将 clara.io 用于商业用途,请与销售团队联系。 18. 3DExport 3DExport是一个市场,您可以在其中购买和销售用于CG项目的3D模型,3D打印模型和纹理。它提供15 +不同的3D格式供下载,如3DS MAX(.max),Cinema4D(.c4d),Maya(.mb,.ma),Lightwave(.lwo),Softimage(.xsi),Wavefront OBJ(.obj),Autodesk FBX(.fbx)等。它还提供15种不同的语言! 使用说明:免费下载仅供个人和非商业用途。 19. 3D Warehouse 3D Warehouse是一个开放的库,允许用户共享和下载SketchUp 3D模型,用于建筑,设计,施工和娱乐!任何人都可以免费制作,修改和重新上传内容到3D仓库,您可以找到任何您能想到的东西,如家具,电子产品,室内产品等。 使用说明:3D Warehouse中的所有模型都是免费的,因此任何人都可以下载文件以用于SketchUp甚至其他软件,如AutoCAD,Revit和ArchiCAD。 20. CadNav.com CadNav是CGI平面设计师和CAD / CAM / CAE工程师的在线3D模型库,我们提供超过50000 +免费3D模型和CAD模型下载。在CadNav网站上,您可以下载高质量的多边形网格3D模型,3D CAD实体对象,纹理,Vray材料,3D作品,CAD图纸等。 使用说明:免费下载仅供个人和非商业用途。 21. All3dfree.net 就像网站名称一样,它提供免费的3D模型,还包括Vray材料,CAD块,2d和3d纹理集合,无需注册即可免费下载。它是不断更新的,因此您可以查找或请求3DS,MAX,C4D,skp,OBJ,FBX,MTL等格式的模型。 使用说明:所有资源均不允许用于商业用途,否则您将承担责任。 22. Hum3D 自2005年以来,Hum3D帮助来自3多个国家的80D艺术家节省3D建模时间,并制作逼真的3D模型,用于电影,视频游戏,AR应用程序和可视化。所有模型均由首席3D艺术家进行验证,他们检查其是否符合专业要求和最新的3D建模标准。 使用说明:免费下载仅供个人和非商业用途。 23. Artist-3D.com 艺术家-3D 库存的免费 3D 模型下载按通用类别排序。它为人体解剖学、汽车、家具、火箭、卫星等模型提供 AutoDesk 3DS Max 格式。您还可以在浏览他们的网站时找到教程和类似类型的建模。 使用说明:使用权限可能因型号而异。因此,在下载文件之前,请仔细检查每个下载页面上的许可证和使用权限。 24. Free the models 就像本网站的标题一样,它为3d应用程序和3d游戏引擎提供免费的内容模型。您可以为您的任何项目找到许多有趣且有用的模型!它提供3ds,wavefront,bryce,poser,lightwave,md2和unity3d格式的模型。还有一个很棒的纹理集合,可以在您最喜欢的建模和渲染程序中使用。 使用说明:您从这里下载的所有内容都可以免费使用,除非它不能包含在另一个免费的网络或CD收藏中,也不能单独出售。否则,您可以在商业游戏,3D应用程序或渲染作品中使用它。您不必提供信用,但如果您这样做,那就太好了。 25. Resources.blogscopia 本网站由一家名为Scopia的公司创建。他们制作3D图像和视频,您可以找到许多为CGI工作的信息架构设计的模型,所有这些都可以在现实生活中使用。您可以免费下载它们,但是,如果您想一次下载它们,您可以支付 3 到 9 欧元。 使用说明:您可以免费下载模型部分的所有文件。每个压缩文件都包含您也可以在此处找到的许可证。基本上,您可以对文件执行任何操作。唯一的限制是不归属于Scopia的重新分发。 26.ambientCG 1000+公共领域PBR材料适合所有人!环境CG是使用许多不同的方法和资产类型创建的,例如照片纹理(PBR),贴花(PBR),图集(PBR),照片纹理(普通),物质存档(SBSAR),雕刻画笔,3D模型和地形。您可以在所有项目中*使用它们! 使用说明:在 ambientCG 上提供下载的所有 PBR 材料、画笔、照片和 3D 模型均根据知识共享 CC0 1.0 通用许可提供。您可以复制、修改、分发和执行作品,即使是出于商业目的,也无需征得许可。信用将不胜感激。 不要满足于平庸的大理石纹理 - 立即使用我们的免费PBR大理石纹理升级您的3D设计。 27.Pixar One Twenty Eight 这是一个提供官方动画行业经典纹理的网站:皮克斯,创建于 1993 年,该纹理库包括 128 个重复纹理,现在免费提供。 它包含您来到的纹理,包括砖块和动物毛皮。肯定会有一些你可以使用的东西。 使用说明:皮克斯动画工作室的《Pixar One Twenty Eight》根据知识共享署名4.0国际许可协议进行许可。即使出于商业目的,您也可以重新混合、调整和构建您的作品,只要您以相同的条款对新创作进行信用和许可。 访问数以千计的免费纹理并提升您的设计游戏 - 立即开始下载! 28. 3DXO 即使有近 620 个免费贴纸可供下载,3DXO 也不是最大的资源,但它的内容非常有用,不需要注册。无论是简单的墙壁或地板,还是一些奇怪的小东西,您都需要的纹理都可以在此网站上看到。 使用说明:使用权限可能因型号而异。因此,在下载文件之前,请仔细检查每个下载页面上的许可证和使用权限。 29. 3DModelsCC0 3DModelsCC0 与其他产品的不同之处在于它包含超过 250+ 个高质量 3D 模型,并且本网站上的所有内容都是免费的,完全是公共领域!使用我们的模型时无需信用或归属! 使用说明:为每个人提供完全免费的公共领域内容。 30.Sketch up texture club Sketchup Texture Club是一个非营利性的教育和信息门户网站,由3D社区的图像促进协会管理,特别强调面向学生和建筑和室内设计专业人士的可视化和渲染技术,以及所有正在学习3D可视化的人。 使用说明:您无需支付版税或使用费。纹理可以免费下载和使用。不允许将纹理作为竞争产品出售或重新分发,即使图像被修改也是如此。 31. FlippedNormals FlippedNormal 是一个提供计算机图形和 3D 资产的市场,您可以找到许多用于雕刻、建模、纹理、概念艺术、3D 模型、游戏资产或课程的高级资产! 使用说明:使用权限可能因型号而异。因此,在下载文件之前,请仔细检查每个下载页面上的许可证和使用权限。 32. NASA 3D NASA 3D网站是一个在线门户,提供与太空和各种NASA任务相关的大量三维模型和模拟。该网站是用户友好的,并提供有关每个型号的详细信息。该网站允许用户探索和下载几种不同格式的模型,包括 OBJ、STL 和 FBX,只需单击下载按钮即可。 使用说明: 要下载模型,只需单击模型页面上的下载按钮并选择所需的格式。 33. 3DAGOGO (Astroprint) 3DAGOGO 是一个提供广泛 3D 模型的网站,包括角色、车辆和建筑物。3DAGOGO 的独特功能之一是它专注于适合 3D 打印的模型,使其成为希望创建物理原型或模型的设计师的绝佳资源。要使用 3DAGOGO,设计师只需在网站上搜索他们正在寻找的模型类型,然后下载 STL 格式的文件。 使用说明: 要使用 3DAGOGO,只需搜索所需的 3D 模型类型并下载 STL 格式的文件。根据需要自定义模型,并确保在将其用于商业目的之前检查使用权限。 34. FreeCAD FreeCAD是一款了不起的3D建模软件,可让您在计算机上创建令人难以置信的3D设计。该软件可免费下载和使用,它提供了广泛的工具和功能,可用于创建用于各种目的的3D模型。 该网站易于浏览,您可以找到开始使用FreeCAD的所有必要信息。此外,该网站还提供一系列教程和指南,可帮助您了解 3D 建模的来龙去脉。 使用说明: 要下载模型,请访问网站并从库中选择所需的模型。该网站还提供了一系列使用该软件的教程和指南。 35. Pinshape Pinshape是一个提供一系列3D打印模型的网站。网站上提供的型号质量很高,因此您可以确保您的最终印刷产品看起来很棒。该网站提供了广泛的模型,包括从家居用品到小雕像和珠宝的所有物品。 但这还不是Pinshape所能提供的全部!该网站还允许用户上传和共享自己的3D模型。这意味着您不仅可以下载出色的模型,还可以通过分享自己的设计为社区做出贡献。此外,Pinshape 提供了一系列自定义选项,因此您可以调整和调整模型以满足您的特定需求。 使用说明: 要下载模型,请在网站上创建一个帐户,搜索所需的模型,然后单击下载按钮。该网站还为每种型号提供了一系列定制选项。 36.Yeggi Yeggi 提供了大量免费的 3D 模型,您可以下载各种格式的模型,例如 STL、OBJ 和 FBX。该网站易于使用,您可以按关键字、类别或特定网站搜索模型。 Yeggi 对于任何寻找 3D 模型的人来说都是一个很好的资源。它提供了大量的模型集合,从日常物品到复杂的机械,以及介于两者之间的一切。该网站的收藏量在不断增长,每天都有新的型号增加。 使用说明: 要下载模型,请在网站上搜索所需的模型,然后单击下载按钮。该网站还提供指向托管模型的原始网站的链接。 37. Open3DModel 来自开放3D模型的图像 Open3DModel具有各种类别的模型,包括建筑,车辆和角色。无论您需要建筑物,汽车还是人的3D模型,都可以在此网站上找到。 该网站易于浏览,您可以按类别或关键字搜索模型。每个模型都附带预览图像和详细信息,例如文件格式、大小和多边形数量。此信息可以帮助您选择适合您需求的模型。 使用说明: 要下载模型,请访问网站,从库中选择所需的模型,然后单击下载按钮。 使用最好的 3D 资产管理工具简化您的 3D 制作流程。立即试用它们,将您的 3D 项目提升到一个新的水平! 38. 3DExport 对于那些为其 3D 设计项目寻找 3D 模型、纹理和其他资源的人来说,该平台是一个很好的资源。该网站有大量模型可供选择,包括 3D 打印对象、游戏资产等。用户可以按类别、文件格式或价格范围浏览,以找到适合其项目的完美资源。此外,3DExport 还提供一系列教程和其他 3D 资源,以帮助用户提高技能并创建更令人印象深刻的设计。 使用说明: 要使用 3DExport,只需创建一个帐户并浏览可用型号。您可以按类别、格式和价格进行搜索,以找到所需的型号。找到喜欢的模型后,只需下载它并开始在您的项目中使用它。 39.Blend Swap Blend Swap是一个社区驱动的市场,提供与Blender软件兼容的各种免费3D模型。该平台允许用户共享和下载模型、纹理和其他资产,以便在他们的项目中使用。 使用说明: 创建免费帐户后,您可以浏览社区上传的大量3D模型。当您找到要使用的一个时,只需下载它并将其导入您选择的 3D 软件即可。 40. 3DShook 3DShook 是一个高级 3D 模型市场,提供一系列用于建筑、游戏等各个行业的高质量模型。该平台提供基于订阅的模型,具有不同的定价计划,允许用户访问一系列模型。 使用说明: 注册免费帐户后,只需浏览3D模型库,选择您喜欢的模型,然后以您需要的格式下载它们。 41. Smithsonian X 3D 史密森尼 X 3D 对于正在寻找历史文物和文物的高质量 3D 模型的设计师来说,这是一个独特的资源。该平台提供了大量3D模型,这些模型是根据史密森尼博物馆和研究中心中的真实物体扫描创建的。 使用说明:
-
C++编程实战 - 第17周:深入探索二进制文件读写操作,终极章来临