C 标准库 IO 使用说明
其实输入与输出对于不管什么系统的设计都是异常重要的,比如设计 C 接口函数,首先要设计好输入参数、输出参数和返回值,接下来才能开始设计具体的实现过程。C 语言标准库提供的接口功能很有限,不像 Python 库。不过想把它用好也不容易,本文总结 C 标准库基础 IO 的常见操作和一些特别需要注意的问题,如果你觉着自己还不是大神,那么请相信我,读完全文后你肯定会有不少收获。
一、操作句柄
打开文件其实就是在操作系统中分配一些资源用于保存该文件的状态信息及文件的标识,以后用户程序可以用这个标识做各种读写操作,关闭文件则释放占用的资源。
打开文件的函数:
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
FILE 是 C 标准库定义的结构体类型,其包含文件在内核中的标识(文件描述符)、I/O 缓冲区和当前读写位置信息,调用者不需知道 FILE 的具体成员,由库函数内部维护,调用者不应该直接访问这些成员。像 FILE* 这样的文件指针称为句柄(Handle)。
打开文件操作是对文件资源进行操作的,所以有可能打开文件失败,所以在打开函数时一定要判断返回值,如果失败则返回错误信息,以方便快速定位错误。
打开文件应该与关闭文件成对存在,虽然程序在退出时会释放相应的资源,但是对于一个长时间运行服务程序来说,经常打开而不关闭文件是会造成进程资源耗尽的,因为进程的文件描述符个数是有限的,及时关闭文件是个好习惯。
关闭文件的函数:
#include <stdio.h>
int fclose(FILE *fp);
fopen 函数参数 mode 总结:
- "r":只读,文件必须存在。
- "w":只写,如果不存在则创建,存在则覆盖。
- "a":追加,如果不存在则创建。
- "r+":允许读和写,文件必须存在。
- "w+":允许读和写,文件不存在则创建,存在则覆盖。
- "a+":允许读和追加,文件不存在则创建。
二、关于stdin/stdout/stderr
在用户程序启动时,main 函数还没开始执行之前,会自动打开三个 FILE* 指针分别是:stdin、stdout、stderr,这三个文件指针是 libc 中定义的全局变量,在 stdio.h 中声明,printf 向 stdout 写,而 scanf 从 stdin 读,用户程序也可以直接使用这三个文件指针。
- stdin 只用于读操作,称为标准输入
- stdout 只用于写操作,称为标准输出
- stderr 也用于写操作,称为标准错误输出
通常程序的运行结果打印到标准输出,而错误提示打印到标准错误输出,一般标准输出和标准错误都是屏幕。通常可以标准输出重定向到一个常规文件,而标准错误输出仍然对应终端设备,这样就可以将运行结果与错误信息分开。
三、以字节为单位的IO函数
fgetc 函数从指定的文件中读一个字节,getchar从标准输入读一个字节,调用 getchar() 相当于 fgetc(stdin)
#include <stdio.h>
int fgetc(FILE *stream);
int getchar(void);
fputc 函数向指定的文件写入一个字节,putchar 向标准输出写一个字节,调用 putchar() 相当于调用 fputc(c, stdout)。
#include <stdio.h>
int fputc(int c, FILE *stream);
int putchar(int c);
参数和返回值类型为什么使用 int 类型?可以看到这几个函数的参数和返回值类型都是 int,而非 unsigned char 型。因为错误或读到文件末尾时将返回 EOF,即 -1,如果返回值是 unsigned char(0xff),与实际读到字节 0xff 无法区分,如果使用 int 就可以避免这个问题。
四、操作读写位置函数
当我们在操作文件时,有一个叫「文件指针」的家伙来记录当前操作的文件位置,比如刚打开文件,调用了 1 次 fgetc 后,此时文件指针指向了第 1 个字节后边,注意是以字节为单位记录的。
改变文件指针位置的函数:
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
whence:从何处开始移动,取值:SEEK_SET | SEEK_CUR | SEEK_END
offset:移动偏移量,取值:可取正 | 负
void rewind(FILE *stream);
举几个简单例子:
fseek(fp, 5, SEEK_SET); // 从文件头向后移动5个字节
fseek(fp, 6, SEEK_CUR); // 从当前位置向后移动6个字节
fseek(fp, -3, SEEK_END); // 从文件尾向前移动3个字节
offset 可正可负,负值表示向文件开头的方向移动,正值表示向文件尾方向移动,如果向前移动的字节数超过文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入会增加文件尺寸,文件空洞字节都是 0
$ echo "5678" > file.txt
fp = fopen("file.txt", "r+");
fseek(fp, 10, SEEK_SET);
fputc('K', fp)
fclose(fp)
// 通过结果可以看出字母K是从第10个位置开始写的
liwei:/tmp$ od -tx1 -tc -Ax file.txt
0000000 35 36 37 38 0a 00 00 00 00 00 4b
5 6 7 8 \n \0 \0 \0 \0 \0 K
rewind(fp) 等价于 fseek(fp, 0, SEEK_SET)
ftell(fp) 函数比较简单,直接返回当前文件指针在文件中的位置
// 实现计算文件字节数的功能
fseek(fp, 0, SEEK_END);
ftell(fp);
五、以字符串为单位的IO函数
fgets 从指定的文件中读一行字符到调用者提供的缓冲区,读入内容不超过 size 。
char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);
首先要说明 gets() 函数强烈不推荐使用,类似 strcpy 函数,用户不可以指定缓冲区大小,很容易造成缓冲区溢出错误。不过 strcpy 程序员还是可以避免,而 gets 的输入用户可以提供任意长的字符串,唯一避免方法就是不使用 gets,而使用 fgets(buf, size, stdin)
fgets 函数从 stream 所指文件读取以 '\n' 结尾的一行,包括 '\n' 在内,存到缓冲区中,并在该行结尾添加一个 '\0' 组成完整的字符串。如果文件一行太长,fgets 从文件中读了 size-1 个字符还没有读到 '\n',就把已经读到的 size-1 个字符和一个 '\0' 字符存入缓冲区,文件行剩余的内容可以在下次调用 fgets 时继续读。
若一次 fgets 调用在读入若干字符后到达文件末尾,则将已读到的字符加上 '\0' 存入缓冲区并返回,如果再次调用则返回 NULL,可以据此判断是否读到文件末尾。
fputs 向指定文件写入一个字符串,缓冲区保存的是以 '\0' 结尾的字符串,与 fgets 不同的是,fputs 不关心字符串中的 '\n' 字符。
int fputs(const char *s, FILE *stream);
int puts(const char *s);
六、以记录为单位的IO函数
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);
fread 和 fwrite 用于读写记录,这里的记录是指一串固定长度的字节,比如一个 int、一个结构体货或一个定长数组。
参数 size 指出一条记录的长度,nmemb 指出要读或写多少条记录,这些记录在 ptr 所指内存空间连续存放,共占 size * nmemb 个字节。
fread 和 fwrite 返回的记录数有可能小于 nmemb 指定的记录数。例如当读写位置距文件末尾只有一条记录长度,调用 fread 指定 nmemb 为 2,则返回值为 1。如果写文件时出错,则 fwrite 的返回值小于 nmemb 指定的值。
struct t{
int a;
short b;
};
struct t val = {1, 2};
FILE *fp = fopen("file.txt", "w");
fwrite(&val, sizeof(val), 1, fp);
fclose(fp);
liwei:/tmp$ od -tx1 -tc -Ax file.txt
0000000 01 00 00 00 02 00 00 00
001 \0 \0 \0 002 \0 \0 \0
从结果可以看出,写入的是 8 个字节,有兴趣的同学可以就此分析下系统的「大小端」和结构体的「对齐补齐」问题。
七、格式化IO函数
(1). printf / scanf
int printf(const char *format, ...);
int scanf(const char *format, ...);
这两个函数是我们学习 C 语言最早接触,可能也是接触比较多的了,没什么特别要说的。printf 就是格式化打印到标准输出。下面总结下 printf 常用的方式。
printf("%d\n", 5); // 打印整数 5
printf("-%10s-\n", "hello") // 设置显示宽度并左对齐:- hello-
printf("-%-10s-\n", "hello") // 设置显示宽度并右对齐:- hello-
printf("%#x\n", 0xff); // 0xff 不加#则显示ff
printf("%p\n", main); // 打印 main 函数首地址
printf("%%\n"); // 打印一个 %
scanf 就是从标准输入中读取格式化数据,简单举个例子:
int year, month, day;
scanf("%d/%d/%d", &year, &month, &day);
printf("year = %d, month = %d, day = %d\n", year, month, day);
(2). sprintf / sscanf / snprintf
sprintf 并不打印到文件,而是打印到用户提供的缓冲区中并在末尾加 '\0',由于格式化后的字符串长度很难预计,所以很可能造成缓冲区溢出,强烈推荐 snprintf 更好一些,参数 size 指定了缓冲区长度,如果格式化后的字符串超过缓冲区长度,snprintf 就把字符串截断到 size - 1 字节,再加上一个 '\0',保证字符串以 '\0' 结尾。如果发生截断,返回值是截断之前的长度,通过对比返回值与缓冲区实际长度对比就知道是否发生截断。
int sscanf(const char *str, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
sscanf 是从输入字符串中按照指定的格式去读取相应的数据,函数功能非常的强大,支持类似正则表达式匹配的功能。具体的使用格式请自行查询官方手册,这里总结出最常用、最重要的几种使用场景和方式。
- 最基本的用法
char buf[1024] = 0;
sscanf("123456", "%s", buf);
printf("%s\n", buf);
// 结果为:123456
- 取指定长度的字符串
sscanf("123456", "%4s", buf);
printf("%s\n", buf);
// 结果为:1234
- 取第1个字符串
sscanf("hello world", "%s", buf);
printf("%s\n", buf);
// 结果为:hello 因为默认是以空格来分割字符串的,%s读取第一个字符串hello
- 读取到指定字符为止的字符串
sscanf("123456#abcdef", "%[^#]", buf);
// 结果为:123456
// %[^#]表示读取到#符号停止,不包括#
- 读取仅包含指定字符集的字符串
sscanf("123456abcdefBCDEF", "%[1-9a-z]", buf);
// 结果为:123456abcdef
// 表达式是要匹配数字和小写字母,匹配到大写字母就停止匹配了。
- 读取指定字符集为止的字符串
sscanf("123456abcdefBCDEF", "%[^A-Z]", buf);
// 结果为:123456abcdef
- 读取两个符号之间的内容(@和.之间的内容)
sscanf("liwei0526vip@linuxblogs.cn", "%*[^@]@%[^.]", buf);
// 结果为:linuxblogs
// 先读取@符号前边内容并丢弃,然后读@,接着读取.符号之前的内容linuxblogs,不包含字符.
- 给一个字符串
sscanf("hello, world", "%*s%s", buf);
// 结果为:world
// 先忽略一个字符串"hello,",遇到空格直接跳过,匹配%s,保存 world 到 buf
// %*s 表示第 1 个匹配到的被过滤掉,即跳过"hello,",如果没有空格,则结果为 NULL
- 稍微复杂点的
sscanf("ABCabcAB=", "%*[A-Z]%*[a-z]%[^a-z=]", buf);
// 结果为:AB 自己尝试分析哈
- 包含特殊字符处理
sscanf("201*1b_-cdZA&", "%[0-9|_|--|a-z|A-Z|&|*]", buf);
// 结果为:201*1b_-cdZA&
如果能将上述几个例子搞明白,相信基本上已经掌握了 sscanf 的用法,实践才是检验真理的唯一标准,只有多使用,多思考才能真正理解它的用法。
(3). fprintf / fscanf
fprintf 打印到指定的文件 stream 中,fscanf 从文件中格式化读取数据,类似 scanf 函数。相关函数的声明如下:
int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
还是通过简单实例来说明基本用法。
FILE *fp = fopen("file.txt", "w");
fprintf(fp, "%d-%s-%f\n", 32, "hello", 0.12);
fclose(fp);
liwei:/tmp$ cat file.txt
32-hello-0.120000
而 fscanf 函数的使用基本上与 sscanf 函数使用方式相同。
八、IO缓冲区
还有个关于 IO 非常重要的概念,就是 IO 缓冲区。
C 标准库为每个打开的文件分配一个 I/O 缓冲区,用户调用读写函数大多数都在 I/O 缓冲区中读写,只有少数请求传递给内核。
以 fgetc/fputc 为例,当第一次调用 fgetc 读一个字节时,fgetc 函数可能通过系统调用进入内核读 1k 字节到缓冲区,然后返回缓冲区中第一个字节给用户,以后用户再调用 fgetc,就直接从缓冲区读取。
另一方面,fputc 通常只是写到缓冲区中,如果缓冲区满了,fputc 就通过系统调用把缓冲区数据传递给内核,内核将数据写回磁盘。如果希望把缓冲区数据立即写入磁盘,可以调用 fflush 函数。
C 标准库 IO 缓冲区有三种类型:全缓冲、行缓冲和无缓冲区,不同类型的缓冲区具有不同的特性。
-
全缓冲
:如果缓冲区写满了就写回内核。常规文件通常是全缓冲的。 -
行缓冲
:如果程序写的数据中有换行符就把这一行写回内核,或者缓冲区满就写回内核。标准输入和标准输出对应终端设备时通常是行缓冲的。 -
无缓冲
:用户程序每次调用库函数做写操作都要通过系统调用写回内核。标准错误输出通常是无缓冲的,用户程序的错误信息可以尽快输出到设备。
printf("hello world");
while(1);
// 运行程序会发现屏幕并没有打印hello world
// 因为缓冲区没满,且没有\n符号
除了写满缓冲区、写入换行符之外,行缓冲还有一种情况会自动做 flush 操作,如果:
- 用户程序调用库函数从无缓冲的文件中读取
- 或从行缓冲的文件中读取,且这次读操作会引发系统调用从内核读取数据,那么会读之前自动 flush 所有行缓冲
- 程序退出时通常也会自动 flush 缓冲区
如果不想完全依赖自动的 flush 操作,可以调用 fflush 函数手动操作。若调用 fflush(NULL) 可以对所有打开文件的 IO 缓冲区做 flush 操作。缓冲区大小也可以自定义设置,一般情况无需设置,默认即可。
上一篇: 自学 C/C++ 有什么难的?
下一篇: c 语言学习指针 - 几个概念的指针
推荐阅读
-
C 标准库 IO 使用说明
-
C 标准库 - 参考手册
-
35 岁实现财务*,腾讯程序员手握2300万提前退休?-1000万房产、1000万腾讯股票、加上300万的现金,一共2300万的财产。有网友算了一笔账,假设1000万的房产用于自住,剩下1300万资产按照平均税后20-50万不等进行计算,大约花上26-60年左右的时间才能赚到这笔钱。也就是说,普通人可能奋斗一辈子,才能赚到这笔钱。在很多人还在为中年危机而惶惶不可终日的时候,有的人的35岁,就已经安全着陆,试问哪个打工人不羡慕?但问题是有这样财富积累必然有像样的实力做靠山。没有人可以不劳而获。 看到这里,肯定有人说,那么对于普通人来说,卷可能真就成了唯一的出路。但是卷也有轻松的卷,“偷懒”的卷法,对于程序员而言,刨除掉一时无法改掉的开会传统占用的大部分时间,如何把有限的时间和精力放在真正重要的架构设计、需求设计上,而不是重复的造*,编码、改bug、手动测试。因此在科技改变生活的今天,学会使用AI工具成为程序员们的必备技能。 以全栈式全自动的软件开发工具飞算SoFlu软件机器人为例,作为全球首款面向微服务架构设计和最佳实践的软件机器人,SoFlu软件机器人改变了原来手工编码的作业模式,通过可视化拖拽方式以及参数配置就能实现等同于编写复杂代码的业务逻辑,在设计业务逻辑时就完成了微服务应用开发,做到“业务即图,图即代码”,实现“软件开发,十倍提效”。 而作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)具有五大核心能力: ● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。 ● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。 ● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。 ● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。 ● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。 以“将文件流转换为File对象”这个需求为例,以下是FuncGPT(慧函数)秒级生成的代码: / 类名:FileConverter // 函数名:convertStreamToFile // 函数功能:将文件流转换为File对象 // POM依赖包:无 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class FileConverter { /** * 将文件流转换为File对象 * @param inputStream 文件流 * @param filePath 文件路径 * @param fileName 文件名 * @return 转换后的File对象 * @throws IOException 如果发生I/O异常 */ public static File convertStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException { File file = new File(filePath + File.separator + fileName); // 创建File对象 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 创建文件输出流 byte buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { // 从文件流读取数据并写入文件 outputStream.write(buffer, 0, bytesRead); } } return file; // 返回转换后的File对象 } } // 函数示例 // 将文件流转换为File对象示例 // 入参:inputStream,文件流 // 入参:filePath,文件路径 // 入参:fileName,文件名 // 出参:file,转换后的File对象 // 调用示例: // InputStream inputStream = new FileInputStream("example.txt"); // String filePath = "C:\\Users\\User\\Documents"; // String fileName = "example.txt"; // File file = FileConverter.convertStreamToFile(inputStream, filePath, fileName); // System.out.println(file.getAbsolutePath); // 输出结果:例如,将文件流转换为File对象后,文件的绝对路径为:C:\Users\User\Documents\example.txt // 则输出结果为:C:\Users\User\Documents\example.txt 通过分析,不难发现以上代码:
-
谈API网关和应用网关--从技术选型谈起:API网关的性能是第一指标,一般会选择Kong、Apisix等基于OpenResty+Lua的高性能网关(得益于Ngnix基于C++的高性能无阻塞网络IO模型),应用网关一般是结合自身业务的技术栈来选择,比如SpringCloud Gateway、Zuul等。当然,这也不是绝对的,如果你对 Kong 非常熟悉,用它来做应用网关也不是不可能。 一些开源网关项目的例子: Kong Apisix 特使 Traefik SpringCloud 网关 Zuul / Zuul2 接下来,我们将重点介绍应用网关。在网格中,应用网关侧重于以下功能(与 API 网关不同) 动态路由 服务发现 服务聚合/协调 可观察性 如果您使用的是 Sping 技术栈,使用 SpringCloud Gateway 和 Zuul 可以轻松重用现有类库,如集成您的注册表,使用 Hystrix、resilience4j 完成熔断和限流功能等,快速完成一个生产级可用应用网关,如果引入新的复杂技术栈 成本将直线上升。根据使用场景的不同,性能有时并不是第一指标,但通常我们很容易陷入性能误区。
-
C 语言标准库(常用函数)说明(附示例 数学公式:math.h
-
C++ 标准库 _Get_unwrapped
-
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++标准库的bitset类型
-
C++ Primer系列第8篇读书笔记:深入理解标准库类型bitset
-
C++ STL标准库:位段 bitset用法 统计1 count any none test set reset flip to_ulong to_string-std::bitset::any