Java学习15(IO基础知识)

news2025/4/6 6:42:39

1、IO流简介?

IO 即 Input/Output,输入和输出。数据输入到计算机内存的过程即输入,反之**输出到外部存储(比如数据库,文件,远程主机)**的过程即输出。数据传输过程类似于水流,因此称为 IO 流。

IO 流在 Java 中分为输入流输出流,而根据数据的处理方式又分为字节流字符流

Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

2、字节流?

2.1 InputStream(字节输入流)

InputStream用于从源头(通常是文件)读取数据(字节信息)到内存中java.io.InputStream抽象类是所有字节输入流的父类。

InputStream 常用方法 :

  • read() :返回输入流中下一个字节的数据。返回的值介于 0 到 255 之间。如果未读取任何字节,则代码返回 -1 ,表示文件结束。
  • read(byte b[ ]) : 从输入流中读取一些字节存储到数组 b 中。如果数组 b 的长度为零,则不读取。如果没有可用字节读取,返回 -1。如果有可用字节读取,则最多读取的字节数最多等于 b.length , 返回读取的字节数。这个方法等价于 read(b, 0, b.length)
  • read(byte b[], int off, int len) :在read(byte b[ ]) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字节数)。
  • skip(long n) :忽略输入流中的 n 个字节 ,返回实际忽略的字节数。
  • available() :返回输入流中可以读取的字节数。
  • close() :关闭输入流释放相关的系统资源。

从 Java 9 开始,InputStream 新增加了多个实用的方法:

  • readAllBytes() :读取输入流中的所有字节,返回字节数组。
  • readNBytes(byte[] b, int off, int len) :阻塞直到读取 len 个字节。
  • transferTo(OutputStream out) : 将所有字节从一个输入流传递到一个输出流。

FileInputStream 是一个比较常用的字节输入流对象,可直接指定文件路径,可以直接读取单字节数据也可以读取至字节数组中

FileInputStream 代码示例:

try (InputStream fis = new FileInputStream("input.txt")) {
    System.out.println("Number of remaining bytes:"
            + fis.available());
    int content;
    long skip = fis.skip(2);
    System.out.println("The actual number of bytes skipped:" + skip);
    System.out.print("The content read from file:");
    while ((content = fis.read()) != -1) {
        System.out.print((char) content);
    }
} catch (IOException e) {
    e.printStackTrace();
}

input.txt 文件内容: LLJavaGuide

输出:

Number of remaining bytes:11
The actual number of bytes skipped:2
The content read from file:JavaGuide

BufferedInputStream:

不过,一般我们是不会直接单独使用 FileInputStream ,通常会配合 BufferedInputStream(字节缓冲输入流,后文会讲到)来使用。像下面这段代码在我们的项目中就比较常见,我们通过 readAllBytes() 读取输入流所有字节并将其直接赋值给一个 String 对象。

// 新建一个 BufferedInputStream 对象
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("input.txt"));
// 读取文件的内容并复制到 String 对象中
String result = new String(bufferedInputStream.readAllBytes());
System.out.println(result);

DataInputStream:

DataInputStream 用于读取指定类型数据,不能单独使用,必须结合 FileInputStream

FileInputStream fileInputStream = new FileInputStream("input.txt");
//必须将fileInputStream作为构造参数才能使用
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
//可以读取任意具体的类型数据
dataInputStream.readBoolean();
dataInputStream.readInt();
dataInputStream.readUTF();

ObjectInputStream和ObjectOutputStream:
在这里插入图片描述

ObjectInputStream 用于从输入流中读取 Java 对象(反序列化)ObjectOutputStream 用于将对象写入到输出流(序列化)

ObjectInputStream input = new ObjectInputStream(new FileInputStream("object.data"));
MyClass object = (MyClass) input.readObject();
input.close();

另外,用于序列化和反序列化的类必须实现 Serializable 接口,对象中如果有属性不想被序列化,声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据。

2.2 OutputStream(字节输出流)

OutputStream用于将数据(字节信息)写入到目的地(通常是文件),java.io.OutputStream抽象类是所有字节输出流的父类。

OutputStream 常用方法 :

  • write(int b) :将特定字节写入输出流。
  • write(byte b[ ]) : 将数组b 写入到输出流,等价于 write(b, 0, b.length) 。
  • write(byte[] b, int off, int len) : 在write(byte b[ ]) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字节数)。
  • flush() :刷新此输出流并强制写出所有缓冲的输出字节。
  • close() :关闭输出流释放相关的系统资源。

FileOutputStream 是最常用的字节输出流对象,可直接指定文件路径,可以直接输出单字节数据,也可以输出指定的字节数组。

FileOutputStream 代码示例:

try (FileOutputStream output = new FileOutputStream("output.txt")) {
    byte[] array = "JavaGuide".getBytes();
    output.write(array);
} catch (IOException e) {
    e.printStackTrace();
}

运行结果:JavaGuide

类似于 FileInputStreamFileOutputStream 通常也会配合 BufferedOutputStream(字节缓冲输出流,后文会讲到)来使用。

BufferedOutputStream:

FileOutputStream fileOutputStream = new FileOutputStream("output.txt");
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream)

DataOutputStream:

DataOutputStream 用于写入指定类型数据,不能单独使用,必须结合 FileOutputStream/

/ 输出流
FileOutputStream fileOutputStream = new FileOutputStream("out.txt");
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
// 输出任意数据类型
dataOutputStream.writeBoolean(true);
dataOutputStream.writeByte(1);

ObjectInputStream:

ObjectInputStream 用于从输入流中读取 Java 对象(ObjectInputStream,反序列化),ObjectOutputStream将对象写入到输出流(ObjectOutputStream,序列化)。

ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("file.txt")
Person person = new Person("Guide哥", "JavaGuide作者");
output.writeObject(person);

3、字符流?

不管是文件读写还是网络发送接收,信息的最小存储单元都是字节。 那为什么 I/O 流操作要分为字节流操作和字符流操作呢?

个人认为主要有两点原因:

  • 字符流是由 Java 虚拟机将字节转换得到的,这个过程还算是比较耗时。
  • 如果我们不知道编码类型就很容易出现乱码问题。

乱码问题这个很容易就可以复现,我们只需要将上面提到的 FileInputStream 代码示例中的 input.txt 文件内容改为中文即可,原代码不需要改动。

可以很明显地看到读取出来的内容已经变成了乱码。因此,I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作

如果音频文件、图片等媒体文件字节流比较好,如果涉及到字符的话使用字符流比较好

字符流默认采用的是 Unicode 编码,我们可以通过构造方法自定义编码。

顺便分享一下之前遇到的笔试题:常用字符编码所占字节数?utf8 :英文占 1 字节,中文占 3 字节,unicode任何字符都占 2 个字节,gbk:英文占 1 字节,中文占 2 字节。

3.1 Reader(字符输入流)

Reader用于从源头(通常是文件)读取数据(字符信息)到内存中java.io.Reader抽象类是所有字符输入流的父类。

Reader 用于读取文本InputStream 用于读取原始字节

Reader 常用方法 :

  • read() : 从输入流读取一个字符。
  • read(char[] cbuf) : 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,等价于 read(cbuf, 0, cbuf.length) 。
  • read(char[] cbuf, int off, int len) :在read(char[] cbuf) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字符数)。
  • skip(long n) :忽略输入流中的 n 个字符 ,返回实际忽略的字符数。
  • close() : 关闭输入流并释放相关的系统资源。

InputStreamReader:

InputStreamReader字节流转换为字符流的桥梁,其子类 FileReader 是基于该基础上的封装,可以直接操作字符文件

// 字节流转换为字符流的桥梁
public class InputStreamReader extends Reader {
}
// 用于读取字符文件
public class FileReader extends InputStreamReader {
}

FileReader 代码示例:

try (FileReader fileReader = new FileReader("input.txt");) {
    int content;
    long skip = fileReader.skip(3);
    System.out.println("The actual number of bytes skipped:" + skip);
    System.out.print("The content read from file:");
    while ((content = fileReader.read()) != -1) {
        System.out.print((char) content);
    }
} catch (IOException e) {
    e.printStackTrace();
}

input.txt 文件内容:你好,我是Guide

输出:

The actual number of bytes skipped:3
The content read from file:我是Guide

3.2 Writer(字符输出流)

Writer用于将数据(字符信息)写入到目的地(通常是文件)java.io.Writer抽象类是所有字符输出流的父类。

Writer 常用方法 :

  • write(int c) : 写入单个字符。
  • write(char[] cbuf) :写入字符数组 cbuf,等价于write(cbuf, 0, cbuf.length)。
  • write(char[] cbuf, int off, int len) :在write(char[] cbuf) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字符数)。
  • write(String str) :写入字符串,等价于 write(str, 0, str.length()) 。
  • write(String str, int off, int len) :在write(String str) 方法的基础上增加了 off 参数(偏移量)和 len 参数(要读取的最大字符数)。
  • append(CharSequence csq) :将指定的字符序列附加到指定的 Writer 对象并返回该 Writer 对象。
  • append(char c) :将指定的字符附加到指定的 Writer 对象并返回该 Writer 对象。
  • flush() :刷新此输出流并强制写出所有缓冲的输出字符
  • close():关闭输出流释放相关的系统资源。

OutputStreamWriter:

OutputStreamWriter字符流转换为字节流的桥梁,其子类 FileWriter 是基于该基础上的封装,可以直接将字符写入到文件。

// 字符流转换为字节流的桥梁
public class OutputStreamWriter extends Writer {
}
// 用于写入字符到文件
public class FileWriter extends OutputStreamWriter {
}

FileWriter 代码示例:

try (Writer output = new FileWriter("output.txt")) {
    output.write("你好,我是Guide。");
} catch (IOException e) {
    e.printStackTrace();
}

输出结果:你好,我是Guide

4、字节缓冲流?

IO 操作是很消耗性能的,缓冲流将数据加载至缓冲区,一次性读取/写入多个字节,从而避免频繁的 IO 操作,提高流的传输效率

字节缓冲流这里采用了装饰器模式来增强 InputStreamOutputStream子类对象的功能。

举个例子,我们可以通过 BufferedInputStream(字节缓冲输入流)来增强 FileInputStream 的功能。

// 新建一个 BufferedInputStream 对象
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("input.txt"));

字节流和字节缓冲流的性能差别主要体现在我们使用两者的时候都是调用 write(int b) 和 read() 这两个一次只读取一个字节的方法的时候差别很大

由于字节缓冲流内部有缓冲区(字节数组),因此,字节缓冲流会先将读取到的字节存放在缓存区,大幅减少 IO 次数,提高读取效率

使用 write(int b) 和 read() 方法,分别通过字节流和字节缓冲流复制一个 524.9 mb 的 PDF 文件耗时对比如下:

使用缓冲流复制PDF文件总耗时:15428 毫秒
使用普通字节流复制PDF文件总耗时:2555062 毫秒

两者耗时差别非常大,缓冲流耗费的时间是字节流的 1/165。测试代码如下:

@Test
void copy_pdf_to_another_pdf_buffer_stream() {
    // 记录开始时间
    long start = System.currentTimeMillis();
    try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("深入理解计算机操作系统.pdf"));
         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("深入理解计算机操作系统-副本.pdf"))) {
        int content;
        while ((content = bis.read()) != -1) {
            bos.write(content);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 记录结束时间
    long end = System.currentTimeMillis();
    System.out.println("使用缓冲流复制PDF文件总耗时:" + (end - start) + " 毫秒");
}

@Test
void copy_pdf_to_another_pdf_stream() {
    // 记录开始时间
    long start = System.currentTimeMillis();
    try (FileInputStream fis = new FileInputStream("深入理解计算机操作系统.pdf");
         FileOutputStream fos = new FileOutputStream("深入理解计算机操作系统-副本.pdf")) {
        int content;
        while ((content = fis.read()) != -1) {
            fos.write(content);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 记录结束时间
    long end = System.currentTimeMillis();
    System.out.println("使用普通流复制PDF文件总耗时:" + (end - start) + " 毫秒");
}

如果是调用 read(byte b[]) 和 write(byte b[], int off, int len) 这两个写入一个字节数组的方法的话,只要字节数组的大小合适,两者的性能差距其实不大,基本可以忽略。

这次我们使用 read(byte b[]) 和 write(byte b[], int off, int len) 方法,分别通过字节流和字节缓冲流复制一个 524.9 mb 的 PDF 文件耗时对比如下:

使用缓冲流复制PDF文件总耗时:695 毫秒
使用普通字节流复制PDF文件总耗时:989 毫秒

两者耗时差别不是很大,缓冲流的性能要略微好一点点。测试代码如下:

@Test
void copy_pdf_to_another_pdf_with_byte_array_buffer_stream() {
    // 记录开始时间
    long start = System.currentTimeMillis();
    try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("深入理解计算机操作系统.pdf"));
         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("深入理解计算机操作系统-副本.pdf"))) {
        int len;
        byte[] bytes = new byte[4 * 1024];
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 记录结束时间
    long end = System.currentTimeMillis();
    System.out.println("使用缓冲流复制PDF文件总耗时:" + (end - start) + " 毫秒");
}

@Test
void copy_pdf_to_another_pdf_with_byte_array_stream() {
    // 记录开始时间
    long start = System.currentTimeMillis();
    try (FileInputStream fis = new FileInputStream("深入理解计算机操作系统.pdf");
         FileOutputStream fos = new FileOutputStream("深入理解计算机操作系统-副本.pdf")) {
        int len;
        byte[] bytes = new byte[4 * 1024];
        while ((len = fis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 记录结束时间
    long end = System.currentTimeMillis();
    System.out.println("使用普通流复制PDF文件总耗时:" + (end - start) + " 毫秒");
}

4.1 BufferedInputStream(字节缓冲输入流)

BufferedInputStream 从源头(通常是文件)读取数据(字节信息)到内存的过程中不会一个字节一个字节的读取而是会先将读取到的字节存放在缓存区,并从内部缓冲区中单独读取字节。这样大幅减少了 IO 次数,提高了读取效率。

BufferedInputStream 内部维护了一个缓冲区,这个缓冲区实际就是一个字节数组,通过阅读 BufferedInputStream 源码即可得到这个结论。

public
class BufferedInputStream extends FilterInputStream {
    // 内部缓冲区数组
    protected volatile byte buf[];
    // 缓冲区的默认大小
    private static int DEFAULT_BUFFER_SIZE = 8192;
    // 使用默认的缓冲区大小
    public BufferedInputStream(InputStream in) {
        this(in, DEFAULT_BUFFER_SIZE);
    }
    // 自定义缓冲区大小
    public BufferedInputStream(InputStream in, int size) {
        super(in);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }
}

缓冲区的大小默认为 8192 字节,当然了,你也可以通过 BufferedInputStream(InputStream in, int size) 这个构造方法来指定缓冲区的大小

4.2 BufferedOutputStream(字节缓冲输出流)

BufferedOutputStream 将数据(字节信息)写入到目的地(通常是文件)的过程中不会一个字节一个字节的写入,而是会先将要写入的字节存放在缓存区,并从内部缓冲区中单独写入字节。这样大幅减少了 IO 次数,提高了读取效率

try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("output.txt"))) {
    byte[] array = "JavaGuide".getBytes();
    bos.write(array);
} catch (IOException e) {
    e.printStackTrace();
}

类似于 BufferedInputStreamBufferedOutputStream 内部也维护了一个缓冲区,并且,这个缓存区的大小也是 8192 字节

5、字符缓冲流BufferedReader (字符缓冲输入流)和 BufferedWriter(字符缓冲输出流)

类似于 BufferedInputStream(字节缓冲输入流)和BufferedOutputStream(字节缓冲输入流),内部都维护了一个字节数组作为缓冲区。不过,前者主要是用来操作字符信息。

6、打印流

System.out.print("Hello!");
System.out.println("Hello!");

System.out 实际是用于获取一个 PrintStream 对象,print方法实际调用的是 PrintStream 对象的 write 方法。

PrintStream 属于字节打印流,与之对应的是 PrintWriter字符打印流)。PrintStream 是 OutputStream 的子类,PrintWriter 是 Writer 的子类。

public class PrintStream extends FilterOutputStream
    implements Appendable, Closeable {
}
public class PrintWriter extends Writer {
}

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

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

相关文章

RocketMQ第一节(MQ的初步了解)

目录 1&#xff1a;什么是消息队列 2&#xff1a;MQ的基础模型 3&#xff1a;MQ的作用 3.1&#xff1a;MQ用来解耦 3.2&#xff1a; 削峰填谷 4&#xff1a;MQ怎么选 1&#xff1a;什么是消息队列 MQ全称是Message Queue (消息队列)&#xff0c;是消息传输中间件&#xf…

FT2000+ qemu kvm 64C64G 通过频繁设置CPU online 状态导致虚拟机假死测试用例

宿主机配置 虚拟机配置文件 <domain typekvm> //如果是Xen&#xff0c;则type‘xen’<name>redflag1</name> //虚拟机名称&#xff0c;同一物理机唯一<uuid>44748c15-7c00-4817-8724-675a27c3f821</uuid> //同一物理机唯一&#xff0c;可用uu…

图形界面GUI相关概念GLX/Wayland/X11/DRM/DRI

1. GUI图形界面是什么 GUI是graphical user interface的缩写&#xff0c;图形用户接口&#xff0c;实现了基本的WIMP&#xff08;windows&#xff0c;icons&#xff0c;menus&#xff0c;pointer&#xff09;。一个GUI的基本组成&#xff1a;display server实现windowing syst…

传统制造企业如何数字化转型?中国减速机Top 1企业给出这份答案

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 数字中国建设正在如火如荼地展开&#xff0c;百业千行也都在寻求自身业务与数字化的深度融合。 2022年制造业增加值占GDP比重约为30%&#xff0c;在数字经济赋能新发展的当下&#xff0c;制造业成为数字技术重点实施落地的载…

2023/4/27总结

第一周任务 - Virtual Judge (vjudge.net) 1.这道题目穷举即可 最多90次 #include<stdio.h> int getLucky(int x) {int a[10],i,n,tx,max0,min10;for(i0;t;i){a[i]t%10;t/10;if(a[i]>max) maxa[i];if(a[i]<min) mina[i];}return max-min; } int slove(int l,int r…

Layui 2.8.1 正式发布,朴实归来

Layui 是一套开源免费的 Web UI 组件库&#xff0c;采用自身轻量级模块化规范&#xff0c;遵循原生态的 HTML/CSS/JavaScript 开发模式&#xff0c;极易上手&#xff0c;拿来即用。其风格简约轻盈&#xff0c;而内在雅致丰盈&#xff0c;甚至包括文档在内的每一处细节都经过精心…

docker部署harbor

Harbor介绍 以Docker为代表的容器技术的出现&#xff0c;改变了传统的交付方式。通过把业务及其依赖的环境打包进Docker镜像&#xff0c;解决了开发环境和生产环境的差异问题&#xff0c;提升了业务交付的效率。如何高效地管理和分发Docker镜像&#xff1f;是众多企业需要考虑…

Shenll编程之循环语句与函数

循环语句 一、for循环二、continue跳出循环continue二次跳出循环 三、break终止循环 循环是一种控制流程的结构&#xff0c;用于重复执行一段代码 遍历是一种数据操作的过程&#xff0c;用于访问并处理数据构成中的每个元素 在某些情况下&#xff0c;循环和遍历可以结合使用&am…

c++标准模板(STL)(std::array)(二)

定义于头文件 <array> template< class T, std::size_t N > struct array;(C11 起) std::array 是封装固定大小数组的容器。 此容器是一个聚合类型&#xff0c;其语义等同于保有一个 C 风格数组 T[N] 作为其唯一非静态数据成员的结构体。不同于 C 风格数…

苹果id密码忘记了怎么重新设置?请收好这份攻略!

案例&#xff1a;怎么重新设置apple ID密码&#xff1f; 【9敏&#xff01;想下载美颜相机&#xff0c;结果忘记苹果id密码了&#xff0c;有什么方法重新设置吗&#xff1f;】 在日常使用中&#xff0c;我们有时候会遇到忘记苹果ID密码的问题&#xff0c;这时候需要重新设置苹…

车联网OTA安全实践

摘要&#xff1a; 近年来&#xff0c;智能汽车已成为全球汽车产业发展的战略方向&#xff0c;汽车技术与工程核心逐渐从传统硬件层面转移到软件层面&#xff0c;汽车行业已经踏上了软件定义汽车&#xff08;SDV&#xff09;的变革之路。 在SDV的大趋势下&#xff0c;汽车零部件…

界面控件DevExpress WinForm的垂直网格,让数据展示更灵活(二)

DevExpress WinForm Vertical Grid&#xff08;垂直网格&#xff09;组件设计用于提供UI灵活性&#xff0c;它允许显示数据集中的单个行&#xff0c;或在其90度反向网格容器中显示多个数据集行。此外&#xff0c;开发者还可以将其用作属性网格&#xff0c;就像在Visual Studio …

VueBaiDuMap百度地图组件常用案例

VueBaiDuMap获取可视区边界点坐标_毛三仙的博客-CSDN博客【代码】VueBaiDuMap获取可视区边界点坐标。百度地图&#xff0c;左上角左下角右上角右下角坐标https://blog.csdn.net/m0_74149462/article/details/130420983?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%…

《springboot实战》 第十二章 SpringBoot整合swagger-bootstrap-ui

前言 SpringBoot整合swagger&#xff0c;使用swagger-bootstrap-ui美化页面。 1、环境配置 1.1、导入依赖包 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version…

不得不说的结构型模式-代理模式

目录 代理模式&#xff1a; 下面是一个简单的C代码案例 下面是面试中可能遇到的问题&#xff1a; 代理模式&#xff1a; 代理模式是一种结构型设计模式&#xff0c;它通过引入一个代理对象来控制对另一个对象的访问。代理对象充当原始对象的中介&#xff0c;通过拦截对原始…

倾斜摄影超大场景的三维模型的顶层合并的点云抽稀处理技术分析

倾斜摄影超大场景的三维模型的顶层合并的点云抽稀处理技术分析 倾斜摄影超大场景的三维模型的顶层合并需要进行点云抽稀处理&#xff0c;以减小数据量和提高数据处理和展示性能。以下是几种常用的点云抽稀处理技术&#xff1a; 1、体素栅格化&#xff1a;将点云数据转换为3D体…

【TCP 协议】报文格式,数据可靠传输的机制(一)

哈喽&#xff0c;大家好~我是你们的老朋友&#xff1a;保护小周ღ 本期为大家带来的是网络编程的 TCP 传输控制协议的概念 &#xff0c;首先会讲解 TCP 协议的报文格式&#xff0c;在学习报文格式之后&#xff0c;会学习两种 TCP 保证数据可靠传输的机制&#xff0c;确认应答…

getType() 和 getGenericType()的区别

处理泛型时会经常用到这两个方法&#xff0c;但是二者的区别是什么&#xff1f; 先看看官方的解释&#xff1a; getType 》&#xff1a;Returns a Class object that identifies the declared type for the field represented by this Field object. 返回字段对象声明类型的…

nodejs+python+php+springboot+vue 婚庆公司服务网站管理系统

管理员模块 &#xff08;1&#xff09;信息管理模块&#xff1a;对商家和个人的查看&#xff0c;修改。 &#xff08;2&#xff09;留言管理模块&#xff1a;对留言进行管理&#xff0c;确定是否能进行发布&#xff0c;对留言进行回复。 &#xff08;3&#xff09;权限管理&…

Git常用命令2

git commit --amend 有时候我们提交完了才发现漏掉了几个文件没有添加&#xff0c;或者提交信息写错了。 此时&#xff0c;可以运行带有 --amend 选项的提交命令来重新提交,这个命令会将暂存区中的文件提交。 如果自上次提交以来你还未做任何修改&#xff08;例如&#xff0c;…