JavaSE中的IO(输入/输出)字节流字符流

news2024/11/19 15:30:03

JavaSE中的IO(输入/输出)知识是一个广泛的领域,它涵盖了如何在Java程序中进行数据的读取和写入。以下是对JavaSE中IO知识的一个清晰归纳:

一、基础知识

流(Stream)的概念

在这里插入图片描述

流是一组有顺序的、有起点和终点的字节集合,用于数据传输。Java的I/O流提供了读写数据的标准方法。Java的I/O流分为输入流(从其他设备读取数据到内存)和输出流(从内存写出数据到其他设备)。

字节流与字符流

字节流:以字节为单位,读写数据的流。例如,InputStream和OutputStream是字节流的抽象类。
字符流:以字符为单位,读写数据的流。例如,Reader和Writer是字符流的抽象类。

主要类和方法

1. InputStream

字节输入流的抽象类,包含read(), read(byte[] b), close()等方法。下面是一个java代码的示例,说明了InputStream的read()、read(byte[] b)和close()方法的用法:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileInputStream对象
            InputStream inputStream = new FileInputStream("example.txt");

            // 使用read()方法逐个字节读取文件内容并打印
            int data;
            while ((data = inputStream.read()) != -1) {
                System.out.print((char) data);
            }

            // 关闭输入流
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的例子中,我们创建了一个FileInputStream对象来读取名为"example.txt"的文件。然后,使用read()方法逐个字节地读取文件内容,直到读取到文件的末尾(返回-1)。每次读取的字节数据都会被转换为字符并打印出来。

下面是另一个示例,演示了使用read(byte[] b)方法从InputStream中读取多个字节到一个字节数组中:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileInputStream对象
            InputStream inputStream = new FileInputStream("example.txt");

            // 创建一个byte数组用于存储读取的数据
            byte[] buffer = new byte[1024];

            // 使用read(byte[] b)方法读取文件内容并打印
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                System.out.write(buffer, 0, bytesRead);
            }

            // 关闭输入流
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们创建了一个大小为1024的字节数组作为缓冲区。然后,使用read(byte[] b)方法从输入流中读取数据,将读取的字节数保存到bytesRead变量中。接下来,通过System.out.write()方法将读取到的数据以字符的形式打印出来。

最后,我们使用close()方法关闭输入流,确保资源被正确释放。

2.OutputStream

字节输出流的抽象类,包含write(int b), write(byte[] b), close(), flush()等方法。下面是一个java代码的示例,说明了OutputStream的write(int b),write(byte[] b),close()和flush()方法的用法:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class OutputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileOutputStream对象
            OutputStream outputStream = new FileOutputStream("example.txt");

            // 使用write(int b)方法将单个字节写入文件
            outputStream.write(65); // 写入字母"A"

            // 使用write(byte[] b)方法将字节数组写入文件
            byte[] buffer = {66, 67, 68}; // 字节数组包含字母"B"、"C"和"D"
            outputStream.write(buffer);

            // 关闭输出流
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的例子中,我们创建了一个FileOutputStream对象来写入名为"example.txt"的文件。然后,使用write(int b)方法将单个字节写入文件。这里使用了ASCII码值65,代表字母"A"。接下来,使用write(byte[] b)方法将字节数组写入文件。字节数组包含ASCII码值为66、67和68的字节,分别对应字母"B"、“C"和"D”。

最后,我们使用close()方法关闭输出流,确保资源被正确释放。

另外,OutputStream还有一个flush()方法,用于强制将缓冲区中的数据写入到输出流中。下面是一个示例:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class OutputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileOutputStream对象
            OutputStream outputStream = new FileOutputStream("example.txt");

            // 使用write()方法将字节写入缓冲区
            outputStream.write(65); // 写入字母"A"

            // 使用flush()方法强制将缓冲区中的数据写入输出流
            outputStream.flush();

            // 关闭输出流
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们写入了字母"A"到输出流的缓冲区中,然后使用flush()方法将缓冲区中的数据强制写入输出流。

这些是OutputStream的基本用法,可以通过这些方法将字节写入到输出流中。

3.Reader和Writer

分别为字符输入流和字符输出流的抽象类,提供了类似字节流的方法,但操作的是字符。下面是一个java代码的示例,说明了Reader和Writer的基本用法:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;

public class ReaderWriterExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileReader对象来读取文件
            Reader reader = new FileReader("input.txt");

            // 创建一个FileWriter对象来写入文件
            Writer writer = new FileWriter("output.txt");

            // 使用read()方法逐个字符读取文件内容并写入输出文件
            int character;
            while ((character = reader.read()) != -1) {
                writer.write(character);
            }

            // 关闭输入和输出流
            reader.close();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的例子中,我们创建了一个FileReader对象来读取名为"input.txt"的文件。然后,我们创建了一个FileWriter对象来写入名为"output.txt"的文件。使用read()方法逐个字符地读取输入文件的内容,并使用write()方法将字符写入输出文件。

最后,我们使用close()方法关闭输入和输出流,确保资源被正确释放。

这些是Reader和Writer的基本用法,可以通过这些方法进行字符的输入和输出操作。

二、常用子类

1.文件流

FileInputStream和FileOutputStream:用于从文件和向文件读写字节。
FileReader和FileWriter:用于从文件和向文件读写字符。
字节流适用于处理二进制数据,字符流适用于处理文本数据。对于文本数据,推荐使用字符流,因为字符流可以自动处理字符编码的转换,而字节流需要手动进行编码和解码操作。
下面是一个Java代码示例,分别使用FileInputStream、FileOutputStream、FileReader和FileWriter来读写字节和字符:

使用FileInputStream和FileOutputStream读写字节:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileInputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileInputStream对象来读取文件
            FileInputStream fis = new FileInputStream("input.txt");

            // 创建一个FileOutputStream对象来写入文件
            FileOutputStream fos = new FileOutputStream("output.txt");

            // 使用read()方法读取字节,并使用write()方法写入字节
            int data;
            while ((data = fis.read()) != -1) {
                fos.write(data);
            }

            // 关闭输入和输出流
            fis.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用FileReader和FileWriter读写字符:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileReaderWriterExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileReader对象来读取文件
            FileReader fr = new FileReader("input.txt");

            // 创建一个FileWriter对象来写入文件
            FileWriter fw = new FileWriter("output.txt");

            // 使用read()方法读取字符,并使用write()方法写入字符
            int data;
            while ((data = fr.read()) != -1) {
                fw.write(data);
            }

            // 关闭输入和输出流
            fr.close();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这两个例子中,我们使用了不同的输入流和输出流来进行字节和字符的读写操作。在读取文件时,我们使用read()方法读取每个字节或字符,并使用write()方法将字节或字符写入输出文件。

最后,我们使用close()方法关闭输入和输出流,确保资源被正确释放。

这些是使用FileInputStream、FileOutputStream、FileReader和FileWriter进行字节和字符读写的基本示例。

2.缓冲流

BufferedInputStream和BufferedOutputStream:提供了带缓冲区的字节流,可以提高读写效率。
BufferedReader和BufferedWriter:提供了带缓冲区的字符流。

下面我将用代码举例说明如何使用BufferedInputStream和BufferedOutputStream以及BufferedReader和BufferedWriter。

  1. 使用BufferedInputStream和BufferedOutputStream从文件中读取和写入字节:
import java.io.*;

public class BufferedStreamExample {
    public static void main(String[] args) {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile))) {

            int bufferSize = 1024;
            byte[] buffer = new byte[bufferSize];
            int bytesRead;

            while ((bytesRead = bis.read(buffer, 0, bufferSize)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }

            System.out.println("File copied successfully!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,我们使用BufferedInputStream从名为"source.txt"的文件中读取字节,并使用BufferedOutputStream将字节写入名为"target.txt"的文件中。我们使用了一个内部缓冲区,大小为1024字节,并循环读取和写入缓冲区中的字节。

  1. 使用BufferedReader和BufferedWriter从文件中读取和写入字符:
import java.io.*;

public class BufferedWriterExample {
    public static void main(String[] args) {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";

        try (BufferedReader reader = new BufferedReader(new FileReader(sourceFile));
             BufferedWriter writer = new BufferedWriter(new FileWriter(targetFile))) {

            String line;

            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine();
            }

            System.out.println("File copied successfully!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,我们使用BufferedReader从名为"source.txt"的文件中读取字符,并使用BufferedWriter将字符写入名为"target.txt"的文件中。我们循环读取每一行字符,并将其写入目标文件。我们使用了一个内部缓冲区来提高读写效率,并使用writer.newLine()方法在每个写入行的末尾添加一个换行符。

这些示例演示了如何使用缓冲流来提高读写操作的效率,并且适用于处理字节和字符数据。请注意,使用完缓冲流后,我们需要及时关闭它们,以确保资源被释放。以上示例中使用了try-with-resources语句,可以在不需要显式关闭流的情况下自动关闭它们。

3.转换流

InputStreamReader和OutputStreamWriter:用于在字节流和字符流之间进行转换。

InputStreamReader是将字节流转换为字符流的桥梁。它读取字节并使用指定的字符编码将其转换为字符。它提供了读取字符的方法,比如read()和readLine()。

OutputStreamWriter则是将字符流转换为字节流的桥梁。它将字符写入输出流,并使用指定的字符编码将其转换为字节。它提供了写入字符的方法,比如write()和flush()。

下面是一个示例,展示如何使用InputStreamReader和OutputStreamWriter进行字节流和字符流的转换:

import java.io.*;

public class InputStreamReaderExample {
    public static void main(String[] args) {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";

        try (FileInputStream fis = new FileInputStream(sourceFile);
             FileOutputStream fos = new FileOutputStream(targetFile);
             InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
             OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8")) {

            int c;

            while ((c = isr.read()) != -1) {
                osw.write(c);
            }

            System.out.println("File converted successfully!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,我们使用FileInputStream从名为"source.txt"的文件中读取字节。然后,我们使用InputStreamReader将字节流转换为字符流,并指定了字符编码为UTF-8。接着,我们使用FileOutputStream将字符流转换为字节流,并指定了字符编码为UTF-8。最后,我们使用OutputStreamWriter将字符写入名为"target.txt"的文件中。

请注意,示例中的try-with-resources语句用于自动关闭流。此外,我们还可以在InputStreamReader和OutputStreamWriter的构造函数中指定其他的字符编码,以根据实际需求进行转换。

三、其他重要概念

1.编码:

不同的编码方式会影响字符和字节之间的转换。常见的编码方式有GBK、UTF-8、UTF-16等。

2.File类:

java.io.File类用于表示文件或目录,提供了许多操作文件和目录的方法,如创建、删除、判断是否存在等。
当使用File类时,我们可以使用下面的几个例子来说明它的用法:

  1. 创建文件:
File file = new File("path/to/file.txt");
try {
  boolean created = file.createNewFile();
  if (created) {
    System.out.println("文件创建成功!");
  } else {
    System.out.println("文件已存在!");
  }
} catch (IOException e) {
  e.printStackTrace();
}
  1. 创建目录:
File dir = new File("path/to/directory");
boolean created = dir.mkdir();
if (created) {
  System.out.println("目录创建成功!");
} else {
  System.out.println("目录已存在!");
}
  1. 删除文件:
File file = new File("path/to/file.txt");
boolean deleted = file.delete();
if (deleted) {
  System.out.println("文件删除成功!");
} else {
  System.out.println("文件不存在或删除失败!");
}
  1. 判断文件是否存在并获取文件属性:
File file = new File("path/to/file.txt");
if (file.exists()) {
  System.out.println("文件存在!");
  System.out.println("文件路径:" + file.getPath());
  System.out.println("文件大小:" + file.length() + "字节");
  System.out.println("最后修改时间:" + new Date(file.lastModified()));
} else {
  System.out.println("文件不存在!");
}
  1. 重命名文件:
File file = new File("path/to/file.txt");
File renamedFile = new File("path/to/renamedFile.txt");
boolean renamed = file.renameTo(renamedFile);
if (renamed) {
  System.out.println("文件重命名成功!");
} else {
  System.out.println("文件重命名失败!");
}

RandomAccessFile类:
RandomAccessFile类是Java提供的一个用于随机访问文件的类。它既可以读取文件内容,也可以向文件中写入数据,并且可以在文件中定位到指定的位置进行读写操作。

下面是一些RandomAccessFile类的例子:

  1. 读取文件内容:
RandomAccessFile raf = new RandomAccessFile("path/to/file.txt", "r");
byte[] buffer = new byte[1024];
int bytesRead = raf.read(buffer);
String contents = new String(buffer, 0, bytesRead);
System.out.println("文件内容:" + contents);
raf.close();
  1. 向文件中写入数据:
RandomAccessFile raf = new RandomAccessFile("path/to/file.txt", "rw");
String data = "Hello, world!";
raf.write(data.getBytes());
raf.close();
System.out.println("数据已写入文件!");
  1. 定位到指定位置进行读写操作:
RandomAccessFile raf = new RandomAccessFile("path/to/file.txt", "rw");
raf.seek(10); // 定位到文件的第10个字节处
byte[] buffer = new byte[1024];
int bytesRead = raf.read(buffer);
String contents = new String(buffer, 0, bytesRead);
System.out.println("文件内容:" + contents);
raf.close();

RandomAccessFile类还提供了其他方法,如获取文件长度、设置文件指针位置、截取文件等。通过使用RandomAccessFile类,你可以更灵活地读取和写入文件的内容,并且可以随时定位到文件的任意位置进行操作。

3.序列化与反序列化:

序列化和反序列化是Java中用于对象持久化和网络传输的重要概念。

序列化(Serialization)是指将对象转换为字节序列的过程,可以将对象保存在磁盘中或通过网络进行传输。在序列化过程中,对象的状态信息被转换为字节数据,可以包括对象的属性值、方法等信息。Java中的序列化由java.io.Serializable接口实现,只有实现了该接口的类才能被序列化。

下面是一个简单的示例,展示了如何将一个对象进行序列化:

import java.io.*;

public class SerializationExample {
    public static void main(String[] args) {
        // 创建一个对象
        Person person = new Person("John", 25);

        try {
            // 创建一个输出流,并将对象进行序列化
            FileOutputStream fileOut = new FileOutputStream("person.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(person);
            out.close();
            fileOut.close();
            System.out.println("对象已序列化并保存在 person.ser 文件中");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

反序列化(Deserialization)是指将字节序列恢复为对象的过程。反序列化可以从磁盘文件或网络传输的字节流中恢复出对象的状态信息,并创建一个对象实例。Java中的反序列化通过ObjectInputStream类来实现。

下面是一个简单的示例,展示了如何从文件中反序列化一个对象:

import java.io.*;

public class DeserializationExample {
    public static void main(String[] args) {
        Person person = null;

        try {
            // 创建一个输入流,并从文件中读取字节序列反序列化为对象
            FileInputStream fileIn = new FileInputStream("person.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            person = (Person) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return;
        }

        System.out.println("反序列化后的对象:");
        System.out.println("姓名: " + person.getName());
        System.out.println("年龄: " + person.getAge());
    }
}

注意:要进行序列化和反序列化,对象的类必须加上implements Serializable接口,否则会抛出NotSerializableException异常。序列化是将对象转换为字节序列以便存储或传输的过程,反序列化则是将字节序列恢复为对象的过程。

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

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

相关文章

大模型应用之基于 Langchain 的测试用例生成

一 用例生成实践效果 在组内的日常工作安排中,持续优化测试技术、提高测试效率始终是重点任务。近期,我们在探索实践使用大模型生成测试用例,期望能够借助其强大的自然语言处理能力,自动化地生成更全面和高质量的测试用例。 当前…

【通过新能源汽车的智慧数字底盘技术看计算机的相关技术堆栈?以后是软硬结合的全能程序员的天下,取代全栈(前后端都会的全栈程序员)】

汽车的“智慧数字底盘”是一个综合性的技术平台,旨在提升车辆的性能、安全性和驾驶体验。它集成了多种先进的技术和系统,是全能程序员的必杀技! 1. 传感器技术 a. 激光雷达(LiDAR) 用于生成高分辨率的3D地图&#…

PG sql调优案例学习

一,开发范式 1.不要轻易把字段嵌入到表达式 例:在sal列上有索引,但是条件语句中把sal列放在了表达式当中,导致索引被压抑,因为索引里面储存的是sal列的值,而不是sal加上100以后的值。 在条件中查询谁的工资1002000。这样写即使在sal上有索引也会走全表…

【倪诗韵神品连珠琴】音质纯净共鸣好,漆髹水墨黑云纹,讲究

【倪诗韵神品连珠琴】音质纯净共鸣好,漆髹水墨黑云纹,用料讲究。 此琴音质纯净共鸣好,非常清透,适合清风清新俊逸之流,琴体造型秀气,漆髹水墨黑云纹,用料讲究,木材纹理竖直而无疤。琴…

【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版7(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言绘制进度条UI控制关卡进度测试按配置表使用关卡进度变化源码结束语 前言 本节主要实现关卡进度条的功能 绘制进度条UI 控制关卡进度测试 新增ProgressPanel代码,控制关卡进度 public class ProgressPanel : Mon…

kettle学习(利用jsonPath定位,json文件转换)

kettle学习(利用jsonPath定位,json文件转换) 于数据处理的广袤天地间,我们时常需应对各类繁杂状况与各式格式。Kettle 作为极具威力的数据集成利器,赋予了我们诸多功能与无限可能此次博客里,我们将重点投向…

一站到底-Vue移动端从零到一构建高效应用

​🌈个人主页:前端青山 🔥系列专栏:vue篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:一文精通Vue移动端:从零到一构建高效应用 目录 1、项目创建 2、引入组件库 二、功能实…

上位机图像处理和嵌入式模块部署(f407 mcu内部flash编程)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 对于f407这样的mcu来说,有的时候我们需要对mcu内部的flash进行编程处理。有两种情况需要对flash进行编程,一种情况是可能一…

深度学习500问——Chapter10:迁移学习(2)

文章目录 11.2 迁移学习的基本思路有哪些 11.2.1 基于样本迁移 11.2.2 基于特征迁移 11.2.3 基于模型迁移 11.2.4 基于关系迁移 11.2 迁移学习的基本思路有哪些 迁移学习的基本方法可以分为四种。这四种基本方法分别是:基于样本的迁移,基于模型的迁移&a…

电子元器件批发的几种模式

电子元器件的批发模式多种多样,以下是几种常见的模式: 传统批发模式:传统的电子元器件批发模式是指厂商或代理商通过与制造商签订合同,大批量购买元器件,并将其以较低的价格批发给零售商或其他中小型企业。这种模式通常…

树-二叉树的最大路径和

一、问题描述 二、解题思路 因为各个节点的值可能为负数,初始化res(最大路径和)的值为最小整数:Integer.MIN_VALUE 我们这里使用深度遍历(递归)的方法,先看某一个子树的情况: 这里有一个技巧,…

【C#】pdf按页分割文件,以及分页合并,效果还不错,你值得拥有

欢迎来到《小5讲堂》 这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解。 温馨提示:博主能力有限,理解水平有限,若有不对之处望指正! 目录 背景效果单页分割文件合并多页分割插件说明相关文章 背景 最近遇到一…

STM32Cube系列教程11:STM32 AES加解密模块性能测试

文章目录 本次测试环境本次测试所使用的系统时钟为48MHz本次测试主要测试对大量数据进行加解密所需的时间,本次为不严谨测试,忽略了程序调用耗时,结果仅供参考。 AES算法与数据加解密加密与解密对称加解密AES算法AES-ECBAES-CBC 填充算法PKCS…

ITIL简介重要组成部分

ITIL简介&重要组成部分 ITIL(Information Technology Infrastructure Library)是一个IT服务管理的最佳实践框架,通过服务战略、服务设计、服务过渡、服务运营和持续服务改进五个核心模块,帮助组织优化IT服务流程,…

嘴尚绝卤味:健康美味,引领卤味新风尚

在快节奏的现代生活中,人们对于美食的追求从未停歇。卤味作为中国传统美食的代表之一,以其独特的口感和丰富的营养,深受广大消费者的喜爱。而在众多卤味品牌中,嘴尚绝卤味凭借其健康、美味的特色,成为了市场上的佼佼者…

Pytorch解决 多元回归 问题的算法

Pytorch解决 多元回归 问题的算法 回归是一种基本的统计建模技术,用于建立因变量与一个或多个自变量之间的关系。 我们将使用 PyTorch(一种流行的深度学习框架)来开发和训练线性回归模型。 二元回归的简单示例 训练数据集(可获取&…

分离式光电液位传感器有哪些特点?

分离式光电液位传感器是一种先进的液位检测技术,在科学技术的不断推进下得到了广泛应用。相比传统的液位传感器,分离式光电液位传感器具有许多独特的特点。 传感器采用了先进的光学技术,将传感器装在需要检测液位的位置,并采用了…

非GIS专业,真的不适合WebGIS开发吗?

到底是哪些人在新中地特训营学GIS开发? 很多同学对GIS开发的认知还停留在GIS专业的学生才能学GIS开发,然而,在新中地教育,非GIS专业的学生几乎占一半。 除了GIS专业,还有测绘、遥感等跟GIS差别不大的专业学生选择来学…

面试官:你讲下接口防重放如何处理?

前言 我们的API接口都是提供给第三方服务/客户端调用,所有请求地址以及请求参数都是暴露给用户的。 我们每次请求一个HTTP请求,用户都可以通过F12,或者抓包工具fd看到请求的URL链接,然后copy出来。这样是非常不安全的,有人可能会…

鸿蒙轻内核A核源码分析系列二 数据结构-位图操作

在进一步分析之前,本文我们先来熟悉下OpenHarmony鸿蒙轻内核提供的位操作模块,在互斥锁等模块对位操作有使用。位操作是指对二进制数的bit位进行操作。程序可以设置某一变量为状态字,状态字中的每一bit位(标志位)可以具…