百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Java路径-20-Java的Stream、File、IO

toyiye 2024-08-13 11:42 8 浏览 0 评论

1 Java流(Stream)

Java Stream(流)是Java 8引入的一个强大的新特性,用于处理集合数据。它提供了一种更简洁、更灵活的方式来操作数据,可以大大提高代码的可读性和可维护性。

1.1 什么是Stream流?

在开始介绍Java Stream流之前,让我们先了解一下什么是流。流是一系列元素的序列,它可以在一次遍历的过程中逐个处理这些元素。在Java中,流是对数据的抽象,可以操作各种不同类型的数据源,如集合、数组、文件等。

Stream流的主要特点包括:

  • 链式调用:可以通过一系列的方法调用来定义对流的操作,使代码更具可读性。
  • 惰性求值:流上的操作不会立即执行,只有在遇到终端操作时才会触发计算。
  • 函数式编程:流操作使用了函数式编程的思想,可以通过Lambda表达式来定义操作。
  • 并行处理:可以轻松地将流操作并行化,充分利用多核处理器的性能。

1.2 创建Stream流

在使用Java Stream流之前,首先需要创建一个流。流可以从各种数据源中创建,包括集合、数组、文件等。

(1)从集合创建流

可以使用集合的stream()方法来创建一个流。例如:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
Stream<String> stream = names.stream();

(2)从数组创建流

可以使用Arrays.stream()方法来从数组中创建一个流。例如:

int[] numbers = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(numbers);

(3)从文件创建流

可以使用Files.lines()方法来从文件中创建一个流。例如:

try (Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())) {
    // 处理文件中的每一行数据
    lines.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}

1.3 流的操作

一旦创建了流,就可以对其进行各种操作。流的操作可以分为两类:中间操作和终端操作。

1.3.1 中间操作

中间操作是对流的一系列处理步骤,这些步骤会返回一个新的流,允许链式调用。中间操作通常用于对数据进行过滤、映射、排序等操作。一些常见的中间操作包括:

  • filter(Predicate<T> predicate):根据条件过滤元素。
  • map(Function<T, R> mapper):将元素映射为新的值。
  • sorted():对元素进行排序。
  • distinct():去重,去除重复的元素。
  • limit(long maxSize):限制流中元素的数量。
  • skip(long n):跳过流中的前n个元素。

例如,以下代码将对一个整数集合进行筛选、映射和排序操作:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result = numbers.stream()
    .filter(n -> n % 2 == 0) // 过滤偶数
    .map(n -> n * 2)         // 映射为原来的2倍
    .sorted()                // 排序
    .collect(Collectors.toList()); // 收集结果

1.3.2 终端操作

终端操作是流的最后一步操作,它会触发对流的计算并产生一个最终的结果。终端操作通常包括:

  • forEach(Consumer<T> action):对流中的每个元素执行操作。
  • collect(Collector<T, A, R> collector):将流中的元素收集到一个容器中。
  • toArray():将流中的元素收集到数组中。
  • reduce(identity, accumulator):对流中的元素进行归约操作,返回一个值。
  • count():返回流中元素的数量。
  • min(comparator):返回流中的最小元素。
  • max(comparator):返回流中的最大元素。
  • allMatch(predicate):检查流中的所有元素是否都满足条件。
  • anyMatch(predicate):检查流中是否存在满足条件的元素。
  • noneMatch(predicate):检查流中是否没有元素满足条件。
  • findFirst():返回流中的第一个元素。
  • findAny():返回流中的任意一个元素。

终端操作是流的最后一步,一旦调用终端操作,流将被消耗,不能再被复用。

1.3.3 示例:从集合中筛选特定条件的元素

让我们通过一个示例来演示Java Stream流的使用。假设我们有一个包含学生对象的集合,每个学生对象都有姓名、年龄和成绩属性。我们想从集合中筛选出年龄大于18岁且成绩优秀的学生。

class Student {
    private String name;
    private int age;
    private double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public double getScore() {
        return score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}

public class Main {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Alice", 20, 90.0),
            new Student("Bob", 22, 85.5),
            new Student("Charlie", 19, 88.5),
            new Student("David", 21, 92.0),
            new Student("Eva", 18, 94.5)
        );

        List<Student> result = students.stream()
            .filter(student -> student.getAge() > 18 && student.getScore() >= 90.0)
            .collect(Collectors.toList());

        result.forEach(System.out::println);
    }
}

运行以上代码,将输出符合条件的学生信息:

Student{name='Alice', age=20, score=90.0}
Student{name='David', age=21, score=92.0}

1.4 并行流

Java Stream还提供了并行流的支持,可以充分利用多核处理器的性能。只需将普通流转换为并行流,即可实现并行化处理。

List<Student> result = students.parallelStream()
    .filter(student -> student.getAge() > 18 && student.getScore() >= 90.0)
    .collect(Collectors.toList());

需要注意的是,并行流在某些情况下可能会引发线程安全问题,因此在处理共享状态时要格外小心。

1.5 更多方法

当使用Java Stream流进行数据处理时,除了基本的过滤、映射、排序和归约等操作外,还有许多其他有用的中间操作和终端操作。在本节中,我将介绍一些常见的Stream流操作,帮助你更好地理解如何使用它们。

1.5.1 中间操作

(1) distinct()

distinct()方法用于去除流中的重复元素,返回一个去重后的新流。

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> distinctNumbers = numbers.stream()
    .distinct()
    .collect(Collectors.toList());

System.out.println(distinctNumbers); // 输出: [1, 2, 3, 4, 5]

(2)limit(n)

limit(n)方法用于截取流中的前n个元素,返回一个包含前n个元素的新流。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> limitedNumbers = numbers.stream()
    .limit(5)
    .collect(Collectors.toList());

System.out.println(limitedNumbers); // 输出: [1, 2, 3, 4, 5]

(3)skip(n)

skip(n)方法用于跳过流中的前n个元素,返回一个跳过前n个元素后的新流。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> skippedNumbers = numbers.stream()
    .skip(5)
    .collect(Collectors.toList());

System.out.println(skippedNumbers); // 输出: [6, 7, 8, 9, 10]

(4) flatMap()

flatMap()方法用于将流中的每个元素映射成一个新的流,然后将这些新流合并成一个流。通常用于将嵌套的集合扁平化。

List<List<Integer>> nestedLists = Arrays.asList(
    Arrays.asList(1, 2),
    Arrays.asList(3, 4),
    Arrays.asList(5, 6)
);

List<Integer> flattenedList = nestedLists.stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList());

System.out.println(flattenedList); // 输出: [1, 2, 3, 4, 5, 6]

1.5.2 终端操作

(1)forEach()

forEach()方法用于对流中的每个元素执行指定的操作。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
    .forEach(name -> System.out.println("Hello, " + name));

(2)toArray()

toArray()方法用于将流中的元素收集到数组中。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Integer[] numberArray = numbers.stream()
    .toArray(Integer[]::new);

(3)reduce(identity, accumulator)

reduce()方法用于对流中的元素进行归约操作,返回一个值。identity是初始值,accumulator是归约函数。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
    .reduce(0, (a, b) -> a + b);

System.out.println(sum); // 输出: 15

(4)collect()

collect()方法用于将流中的元素收集到一个集合或其他数据结构中。可以使用Collectors类提供的各种工厂方法创建不同类型的集合。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> collectedNames = names.stream()
    .collect(Collectors.toList());

Set<String> collectedSet = names.stream()
    .collect(Collectors.toSet());

Map<String, Integer> collectedMap = names.stream()
    .collect(Collectors.toMap(name -> name, String::length));

(5)min(comparator)max(comparator)

min(comparator)max(comparator)方法用于查找流中的最小和最大元素,需要传入一个比较器(Comparator)来定义比较规则。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> minNumber = numbers.stream()
    .min(Integer::compareTo);

Optional<Integer> maxNumber = numbers.stream()
    .max(Integer::compareTo);

System.out.println(minNumber.orElse(0)); // 输出: 1
System.out.println(maxNumber.orElse(0)); // 输出: 5

(6)anyMatch(predicate)allMatch(predicate)noneMatch(predicate)

这些方法用于检查流中的元素是否满足给定的条件。

  • anyMatch(predicate):检查流中是否有任意一个元素满足条件。
  • allMatch(predicate):检查流中的所有元素是否都满足条件。
  • noneMatch(predicate):检查流中是否没有元素满足条件。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyGreaterThanThree = numbers.stream()
    .anyMatch(n -> n > 3);

boolean allGreaterThanThree = numbers.stream()
    .allMatch(n -> n > 3);

boolean noneGreaterThanTen = numbers.stream()
    .noneMatch(n -> n > 10);

System.out.println(anyGreaterThanThree); // 输出: true
System.out.println(allGreaterThanThree); // 输出: false
System.out.println(noneGreaterThanTen);  // 输出: true

(7)findFirst()findAny()

findFirst()方法返回流中的第一个元素(在串行流中通常是第一个元素,但在并行流中不确定),findAny()方法返回流中的任意一个元素。

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Optional<String> first = names.stream()
    .findFirst();

Optional<String> any = names.parallelStream()
    .findAny();

这些只是Java Stream流的一些常见操作,Stream API提供了更多的方法来处理数据。根据具体的需求,你可以组合这些操作来构建复杂的数据处理流程。希望这些示例能帮助你更好地理解和使用Java Stream流。

1.6 注意事项

在使用Java Stream流时,有一些注意事项需要考虑,以确保代码的正确性和性能。以下是一些常见的注意事项:

  1. 不可重用性: 一旦创建了一个Stream对象并执行了终端操作,该Stream就不能再被重用。如果需要对同一数据集进行多次处理,应该每次都创建新的Stream对象。
  2. 惰性求值: Stream是惰性求值的,中间操作只会在终端操作触发后才会执行。这意味着中间操作不会立即产生结果,而是在需要结果时才进行计算。这可以帮助节省计算资源,但也需要谨慎处理,以免产生意外的行为。
  3. 并行流的线程安全性: 如果使用并行流(parallelStream()),要确保Stream操作是线程安全的。一些操作可能会引发并发问题,需要适当的同步或避免使用并行流。
  4. 流的关闭: 如果你使用的是基于IO的流(如Files.lines()),需要确保在使用完后关闭流,以释放资源。
  5. 性能注意事项: Stream操作的性能可能会受到数据量的影响。在大数据集上使用Stream时,要注意性能问题,可以考虑使用并行流或其他优化方法。
  6. 空值处理: 在使用Stream时,要注意空值(null)的处理,避免空指针异常。可以使用filtermap等操作来过滤或转换空值。
  7. 有状态操作: 一些Stream操作是有状态的,例如sorteddistinct,它们可能需要缓存所有元素,因此在处理大数据集时要谨慎使用,以免导致内存溢出。
  8. 自定义收集器: 如果需要自定义收集器(Collector),要确保它的线程安全性和正确性,以便在Stream中使用。
  9. 不可变性: 推荐使用不可变对象和不可变集合来处理Stream,以避免并发问题。
  10. 了解Stream操作的复杂度: 不同的Stream操作具有不同的时间复杂度。了解操作的复杂度有助于选择最适合的操作来满足性能需求。

总之,使用Java Stream流可以编写更简洁和可读性强的代码,但在使用过程中需要考虑到流的惰性求值、线程安全性、性能等方面的注意事项,以确保代码的正确性和性能。

Java Stream流是一项强大的特性,可以极大地简化集合数据的处理。通过中间操作和终端操作的组合,我们可以轻松地实现各种复杂的数据处理任务。同时,流还提供了并行处理的支持,可以充分利用多核处理器的性能。

要注意的是,流是一次性的,一旦调用了终端操作,流将被消耗,不能再被复用。此外,在使用并行流时要注意线程安全的问题。

2 文件(File)

2.1 概念

File,即文件、文件夹,一个File对象表示了磁盘上的某个文件文件夹在java中,File类实质是以文件或者文件夹的路径来操作的File 类是 java.io 包中唯一代表磁盘文件本身的对象。File类的类图如下 :



File类实现了Serializable和Comparable两个接口。Serializable接口的实现,使File类的对象可以串行化,串行化后,对象可以进行网络传输,也可以保存到文件。而Comparable接口的实现使得File对象可以进行比较。File类以文件或文件夹为单位进行操作,因此不能直接访问文件的内容,若想访问文件内容,需要配合java中的IO流来完成。

java.io.File 类是 Java 中用于处理文件和目录路径的类。它提供了文件和目录的创建、删除、重命名等操作,但不直接用于文件的读写。File 类可以用来获取文件和目录的属性,如大小、修改时间等。

主要功能

  • 文件和目录的创建、删除和重命名createNewFile()delete()renameTo(File dest)
  • 检查文件或目录是否存在exists()
  • 获取文件或目录的属性:如length()(大小)、lastModified()(最后修改时间)。
  • 列出目录内容list()listFiles()
  • 检查是文件还是目录isFile()isDirectory()
  • 创建和删除目录mkdir()mkdirs()rmdir()

2.2 构造方法

1. File (String pathname): 需要传入String类型的文件路径。 需要用File类型作接收。

2. File(String parent, String child): 和第一种构造方式大同小异。不过是将文件路径劈开了,分为父路径和子路径两部分,作为两个形参。

3. File(File parent, String child): 与前两种构造方式略有差异:将文件路径劈开后,又先将父路径封装成了File类型,然后再分别将“File类型的父路径” 和 “String类型的子路径”传上去。

示例代码:

import java.io.File;
import java.io.IOException;
 
public class FileConstructors {
    public static void main (String[] args) throws IOException {//建议直接抛出父类异常
//演示File类的三种构造方法:(1.txt之后会在创建功能的演示中创建)
    //1.File (String pathname):
        File file1 = new File("D:\\JAVA\\IDEA\\1.txt");
        System.out.println("file1对象:\n" + file1);
        System.out.println("---------------------------------");
 
    //2.File(String parent, String child):
        File file2 = new File("D:/JAVA/IDEA/", "2.txt");
        System.out.println("file2对象:\n" + file2);
        System.out.println("---------------------------------");
 
    //3.File(File parent, String child):
        File parent = new File("D:/JAVA/IDEA");
        File file3 = new File(parent, "3.txt");
        System.out.println("file3对象:\n" + file3);
    }
}

输出结果:

file1对象:
D:\JAVAIIDEAl1.txt
file2对象:
D:\JAVA\IDEA\2.txt
file3对象:
D:\JAVA\IDEA\3.txt

2.3 目录路径

在处理文件和目录时,路径有两种不同的表示方式绝对路径相对路径。它们在Java中的java.io.File类和其他相关类中经常使用。

2.3.1 绝对路径

定义:绝对路径是从文件系统的根目录开始的完整路径。它指定了从根目录到文件或目录的确切位置。

特点

  • 不依赖于当前工作目录。
  • 总是以根目录(如Windows中的盘符C:\D:\,或Unix/Linux中的/)开始。
  • 在不同的系统之间通常不可移植。

代码示例(Windows系统)

// 使用绝对路径创建File对象
File absFile = new File("D:\\home\\mixia\\java.txt");
System.out.println("绝对路径: " + absFile.getAbsolutePath());

2.3.2 相对路径

定义:相对路径是相对于当前工作目录的路径。它不指定从根目录开始的完整位置。

特点

  • 依赖于当前工作目录。
  • 不以根目录开始。
  • 在不同的系统之间更易于移植。
// 获取当前工作目录
String workingDirectory = System.getProperty("user.dir");
System.out.println("当前工作目录:" + workingDirectory);

// 使用相对路径创建File对象
File file = new File("uploads/java.txt");
System.out.println("相对路径:" + file.getAbsolutePath());

注意事项

  • 路径分隔符:Windows系统使用反斜杠\作为路径分隔符,而Unix/Linux系统使用斜杠/
  • 在Java中,你可以使用File.separator来获取当前系统的路径分隔符,以确保跨平台兼容性。
  • 当前工作目录:在Java中,当前工作目录通常是启动Java虚拟机时的工作目录。你可以使用System.getProperty("user.dir")来获取当前工作目录的路径。

2.4 常用方法

2.4.1 路径操作

  • String getAbsolutePath():获取文件或目录的绝对路径。
  • String getPath():获取文件或目录的路径。
  • String getName():获取文件或目录的名称。
  • String getParent():获取文件或目录的父路径。
  • File getParentFile():获取文件或目录的父 File 对象。
  • boolean isAbsolute():判断路径是否为绝对路径。
  • File getCanonicalFile():返回此 File 对象的规范路径名形式,处理符号链接等特殊情况。
// 使用相对路径创建File对象
File file = new File("uploads/java.txt");

// 获取文件或目录的绝对路径
System.out.println("相对路径: " + file.getAbsolutePath());
// 获取文件或目录的路径。
System.out.println("路径: " + file.getPath());
// 获取文件或目录的名称。
System.out.println("文件名: " + file.getName());
// 获取文件或目录的父路径。
System.out.println("父路径: " + file.getParent());
// 获取文件或目录的父File对象
System.out.println("父File对象: " + file.getParentFile());
// 判断路径是否为绝对路径。
System.out.println("是否为绝对路径? " + file.isAbsolute());
// 返回此 File 对象的规范路径名形式
System.out.println("规范路径名: "+ file.getCanonicalFile()); // 会有IO异常

2.4.2 文件属性检查

  • boolean exists():判断文件或目录是否存在。
  • boolean isDirectory():判断是否为目录。
  • boolean isFile():判断是否为普通文件。
  • long length():获取文件的长度(字节数)。
  • long lastModified():获取最后一次修改时间(毫秒值)。
// 文件路径
String filePath = "uploads/java.txt";
// 使用相对路径创建File对象
File file = new File(filePath);

// 判断文件或目录是否存在
System.out.println("文件是否存在? " + file.exists());
// 判断是否为目录
System.out.println("判断是否为目录? " + file.isDirectory());
// 判断是否为普通文件
System.out.println("判断是否为普通文件? " + file.isFile());
if (file.isFile()) {
    // 获取文件的长度(字节数)
    System.out.println("文件长度: " + file.length() + " 字节");
    // 获取最后一次修改时间(毫秒值)
    System.out.println("最后修改时间: " + file.lastModified());
}

2.4.3 目录操作

  • String[] list():列出目录下所有子文件和子目录的名称。
String filePath = "uploads/";// 更改为自己想查看的文件路径
// 创建File对象
File file = new File(filePath);
// 列出指定目录下 子文件名和子目录的名称
String[] list = file.list();
// 数组转字符串并输出
System.out.println(Arrays.toString(list));
  • File[] listFiles():列出目录下所有子文件和子目录的 File 对象。
String filePath = "uploads/";// 更改为自己想查看的文件路径
// 创建File对象
File file = new File(filePath);
// 列出目录下所有子文件和子目录的 `File` 对象
File[] filesList = file.listFiles();
// 遍历File对象数组,获取每个子对象
for (File file1 : filesList) {
    System.out.println(file1);
}
  • boolean mkdir():创建一个新的空目录。如果该目录已经存在,此方法将不会做任何事情。
// 要创建的新目录名
String newPath = "new_uploads";
// 创建File对象
File file = new File(newPath);
// 创建目录
boolean is_mkdir = file.mkdir();
if (is_mkdir) {
    System.out.println(newPath + "目录创建成功!");
} else {
    System.out.println(newPath + "目录创建失败!");
}
  • boolean mkdirs():创建多级目录(如果父目录不存在,会一并创建)。
// 要创建的新目录名
String newPath = "dir002/new_uploads";
// 创建File对象
File file = new File(newPath);
// 创建目录
boolean is_mkdir = file.mkdirs();
if (is_mkdir) {
    System.out.println(newPath + "目录创建成功!");
} else {
    System.out.println(newPath + "目录创建失败!");
}
  • boolean delete():删除文件或空目录。
// 要删除的目录
String deletePath = "uploads/dir002/new_uploads";
// 创建 File 类
File file = new File(deletePath);
// 执行删除
boolean isDelete = file.delete();
if (isDelete){
    System.out.println("删除成功!");
}else {
    System.out.println("删除失败!");
}
  • boolean deleteOnExit():注册一个文件,使得在Java虚拟机(JVM)退出时自动删除该文件。这个方法常用于临时文件的处理,确保即使在程序异常终止或忘记手动删除的情况下,临时文件也能被自动清除。
// 要删除的目录
String deletePath = "uploads/dir002";
// 创建一个 File 类
File file = new File(deletePath);
// 执行注册删除(没有返回值)
file.deleteOnExit();

2.4.4 文件操作

  • boolean createNewFile():创建一个新文件。
  • 如果文件不存在,该方法将创建一个新文件,并返回 true
  • 如果文件已存在,则不创建新文件,并返回 false
  • 这个方法常用于确保不会覆盖已存在的文件,同时创建新文件。
// 设置要创建的文件的路径
String filePath = "uploads/dir001/file.txt";
// 创建File类
File fileToCreate  = new File(filePath);
// 创建新文件
try {
    boolean isCreated = fileToCreate.createNewFile();
    if (isCreated) {
        System.out.println("文件已成功创建: " + filePath);
    } else {
        System.out.println("文件已存在: " + filePath);
    }
} catch (IOException e) {
    System.out.println("创建文件时发生错误");
    throw new RuntimeException(e);
}
  • boolean renameTo(File dest):将文件或目录重命名为给定的目标路径。
  • 如果重命名操作成功,则返回 true
  • 如果操作失败,则返回 false
  • 这个方法可以用于移动文件或目录,只需将目标路径设置为不同的目录即可。
// 设置要重命名的文件或目录的路径
String oldPath = "uploads/dir001/file.txt";
// 设置新的文件或目录的路径
String newPath = "uploads/dir001/newFile.txt";

// 创建File对象
File oldFile = new File(oldPath);
File newFile = new File(newPath);

// 尝试重命名文件或目录
boolean isRenamed = oldFile.renameTo(newFile);

if (isRenamed) {
    System.out.println("文件/目录已成功重命名: " + oldPath + " -> " + newPath);
} else {
    System.out.println("重命名文件/目录失败");
}

2.5 注意事项

  • File 类只能操作文件和目录的元数据(如名称、路径、属性),不能用于文件内容的读写。文件内容的读写需要使用输入/输出流(如 FileInputStreamFileOutputStream)。
  • File 类的方法大部分是独立于平台的,但某些操作(如符号链接的处理)可能受底层文件系统的影响。
  • File 类的设计早于Java NIO(New I/O),后者提供了更高级的文件I/O操作。

3 字符流

3.1 概述

在Java中,字符流是用于处理字符数据的输入输出流。它是以字符为单位进行处理,而不是字节。字符流主要用于处理文本文件,可以直接读取和写入字符数据。

Java提供了两种字符流:字符输入流和字符输出流。

  • 字符输入流:

FileReader:用于读取字符数据的输入流。它继承自Reader类,可以读取字符文件的内容。 BufferedReader:用于读取字符数据的缓冲输入流。它继承自Reader类,可以提供更高效的字符读取操作。

  • 字符输出流:

FileWriter:用于写入字符数据的输出流。它继承自Writer类,可以将字符数据写入文件。 BufferedWriter:用于写入字符数据的缓冲输出流。它继承自Writer类,可以提供更高效的字符写入操作。

使用字符流进行读写操作的一般步骤如下:

  1. 创建字符输入流或者字符输出流对象,参数为要读取或写入的文件。
  2. 使用字符输入流或者字符输出流的相应方法进行读取或写入操作。
  3. 关闭字符流。

3.2 字符的编码与解码

字符分为GBK格式和UTF-8格式,当我们想用GBK格式编码的时候就需要用GBK格式进行解码,UTF-8格式同理

//GBK格式
byte[] gbk = "hello java".getByte("GBK");
System.out.println(new String(gbk,"GBK"));
 
//UTF-8格式
byte[] utf = "hello java".getByte("UTF-8");
System.out.println(new String(utf,"UTF-8"));

3.3 字符的读写操作

(1)字符输入流代码示例:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Demo5 {

    public static void main(String[] args) throws IOException{
        FileReader fr=new FileReader(new File("1.txt"));
        char[] ca=new char[1024];
        int count=0;
        while((count=fr.read(ca))!=-1) {
            System.out.println(new String(ca,0,count));
        }
    }
}

(2)字符输出流代码示例:

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

public class Demo6 {

    public static void main(String[] args) throws IOException{
        FileReader fr=new FileReader(new File("1.txt"));
        FileWriter fw=new FileWriter(new File("2.txt"));
        char[] ca=new char[1024];
        int count;
        while((count=fr.read(ca))!=-1) {
            fw.write(ca,0,count);
        }
        fr.close();
        fw.close();
    }
}

字符流与字节流的区别:字符流虽然以字节流为基础创建的,但是字节流可以支持声音,视频,图片,文本等所有文件类型,而字符流只支持文本文件。

(3)带缓冲区BufferReader示例:

带缓冲区的字符输入流:BufferedReader:常用方法:readLine() 读取一行,如果为文件末尾,返回值为null。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Demo7 {

    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new FileReader(new File("1.txt")));
        String value;
        while((value=br.readLine())!=null) {
            System.out.println(value);
        }
        br.close();
    }
}

(4)带缓冲区BufferedWriter示例:

带缓冲区的字符输出流:BufferedWriter:常用方法:writer(string)将字符串写入 到输出流。 newLine()根据系统的行分割符进行换行。

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

public class Demo8 {

    public static void main(String[] args)throws IOException {
        BufferedWriter bw=new BufferedWriter(new FileWriter("3.txt"));
        BufferedReader br=new BufferedReader(new FileReader("1.txt"));
        String value="";
        while((value=br.readLine())!=null) {
            bw.write(value);
            bw.newLine();
        }
        bw.close();
        br.close();
    }
}

使用 BufferedReaderBufferedWriter 可以提高读写效率,因为它们会将数据缓存起来,减少了对文件的实际读写次数。同时,使用 readLine() 可以逐行读取文本数据,方便处理文本文件的内容。

3.4 转换流

(1)InputStreamReader与OutputStreamWriter:

  1. InputStreamReader 将字节流转换成字符流 输入
  2. OutputStreamWriter 将字节流转换成字符流 输出

(2)构造方法:

  • InputStreamReader(InputStream in)
  • InputStreamReader(InputStream in, String cs)
  • OutputStreamWriter(OutputStream out)
  • OutputStreamWriter(OutputStream out, String charsetName)

(3)作用:

  • 可以将字节流转换成字符流
  • 可以使用指定的编码来读取或写入流。

(4)代码示例:

public class Demo10 {
    public static void main(String[] args) throws IOException {
        InputStreamReader is=new InputStreamReader(new FileInputStream(new    File("D:\\6.txt")),"gbk");
        char[] c=new char[1024];
        int value = is.read(c);
        System.out.println(Arrays.toString(c));
    }
}

3.5 对象流、序列化与反序列化

序列化和反序列化是指将对象转换成字节流的过程,以便在需要时可以将字节流重新转换为对象。序列化可以用于对象的持久化存储、网络传输等场景。

在序列化过程中,对象的状态信息(即对象的数据)被转换为字节流,可以通过将字节流写入文件或通过网络传输来保存。反序列化过程恢复字节流,将其转换为原始对象。

序列化和反序列化可以用于不同的编程语言之间的对象传输,因为字节流是一种通用的数据格式。

在Java中,可以使用Serializable接口将对象标记为可序列化的,然后使用ObjectOutputStream将对象序列化为字节流,使用ObjectInputStream将字节流反序列化为对象。

(1)对象流 / 序列化流

  • ObjectInputStream: 反序列化流
  • ObjectOutputStream: 序列化流

(2)常用方法

  • writeObject(obj) 将 obj 对象写入到流中
  • readObject 读取流中的数据
  • EOFException 表示读取流意外读到了文件的末尾 ( 就是一个空文件。 )

(3)构造方法

  • ObjectOutputStream(OutputStream out)
  • ObjectInputStream(InputStream in)

(4)序列化版本号

  • serialVersionUID 序列化版本号:保证序列化流与反序列化流读写一致,保证版本一致性。

代码示例1:

package com.aiowang;  
  
import java.io.*;  
import java.util.ArrayList;  
  
public class Demo1 {  
    public static void main(String[] args) {  
        ArrayList<TeacherDemo> list=new ArrayList<>();  
        list.add(new TeacherDemo(" 张三 ", 18, new ClassRoom("0318java")));  
        list.add(new TeacherDemo(" 李四 ", 18, new ClassRoom("0318java")));  
        list.add(new TeacherDemo(" 王五 ", 18, new ClassRoom("0318java")));  
        // writeToFile(list,"stu.txt");  
        // 读取  
        System.out.println(readTeacher("stu.txt"));  
    }  
    // 带异常处理的 ,序列化  
    public static void writeToFile(ArrayList<TeacherDemo> list, String fileName) {  
    // 序列化流进行写入  
        try(  
                ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File(fileName)));  
        ){  
            oos.writeObject(list);  
        }catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
    // 反序列化  
    public static ArrayList<TeacherDemo> readTeacher(String fileName) {  
        ArrayList<TeacherDemo> list=null;  
        // 反序列化流读取文件中的集合  
        try(  
                ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File(fileName)));  
        ){  
            list = (ArrayList<TeacherDemo>) ois.readObject();  
        }catch (Exception e) {  
            e.printStackTrace();  
        }  
        return list;  
    }  
}  
  
  
class TeacherDemo implements Serializable{  
    /**  
     *  序列化版本号:默认版本号为 1l  
     */    private static final long serialVersionUID = 1L;  
    private String name;  
    private int age;  
    private ClassRoom cn;// 班级  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    }  
    public void setAge(int age) {  
        this.age = age;  
    }  
    public ClassRoom getCn() {  
        return cn;  
    }  
    public void setCn(ClassRoom cn) {  
        this.cn = cn;  
    }  
    @Override  
    public String toString() {  
        return "Teacher [name=" + name + ", age=" + age + ", cn=" + cn + "]";  
    }  
    public TeacherDemo() {  
        super();  
    }  
    public TeacherDemo(String name, int age) {  
        super();  
        this.name = name;  
        this.age = age;  
    }  
  
    public TeacherDemo(String name, int age, ClassRoom cn) {  
        super();  
        this.name = name;  
        this.age = age;  
        this.cn = cn;  
    }  
}  
  
class ClassRoom implements Serializable{  
    /**  
     *  序列化版本号:保证序列化流与反序列化流读写一致  
     */  
    private static final long serialVersionUID = 3359646767342429683L;  
    private String no;  
    public ClassRoom() {  
        super();  
    }  
    public ClassRoom(String no) {  
        super();  
        this.no = no;  
    }  
    @Override  
    public String toString() {  
        return "ClassRoom [no=" + no + "]";  
    }  
    public String getNo() {  
        return no;  
    }  
    public void setNo(String no) {  
        this.no = no;  
    }// 班级号码  
}

代码示例2:

package com.aiowang;  
  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
import java.io.Serializable;  
import java.util.ArrayList;  
import java.util.Iterator;  
  
public class Demo2 {  
  
    public static void main(String[] args)throws IOException, Exception {  
        ArrayList<Student6> list=new ArrayList<>();  
        list.add(new Student6("张三","1001",18));  
        list.add(new Student6("李四","1002",19));  
        list.add(new Student6("王五","1003",20));  
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("4.txt")));  
        oos.writeObject(list);  
        oos.close();  
  
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("4.txt") ));  
        ArrayList<Student6> list2=(ArrayList<Student6>) ois.readObject();  
        Iterator<Student6> it=list2.iterator();  
        while(it.hasNext()) {  
            Student6 stu=it.next();  
            System.out.println("姓名:"+stu.getName()+"\t学号:"+stu.getStuNo()+"\t年龄+\t:"+stu.getAge());  
        }  
    }  
}  
class Student6 implements Serializable{  
    /**  
     *     */    private static final long serialVersionUID = 2658878058482366562L;  
    private String name;  
    private String stuNo;  
    private int age;  
  
    public Student6() {  
        super();  
    }  
    public Student6(String name,String stuNo,int age) {  
        this.name=name;  
        this.stuNo=stuNo;  
        this.age=age;  
  
    }  
    public void setName(String name) {  
        this.name=name;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setStuNo(String stuNo) {  
        this.stuNo=stuNo;  
    }  
    public String getStuNo() {  
        return stuNo;  
    }  
    public void setAge(int age) {  
        this.age=age;  
    }  
    public int getAge() {  
        return age;  
    }  
    @Override  
    public String toString() {  
        return "Student6 [name=" + name + ", stuNo=" + stuNo + ", age=" + age + "]";  
    }  
}

4 字节流

4.1 概述

在计算机中,无论是文本、图片、音频还是视频,所有文件都是以二进制(字节)形式存在的,I/O流中针对字节的输入/输出提供了一系列的流,统称为字节流。

字节流是程序中最常用的流,根据数据的传输方向可将其分为字节输入流和字节输出流。在JDK中,提供了两个抽象类InputStream和OutputStream,它们是字节流的顶级父类,所有的字节输入流都继承自InputStream,所有的字节输出流都继承自OutputStream。

4.2 常用方法

在JDK中,InputStream和 OutputStream 提供了一系列与读写数据相关的方法。

InputStream 的常用方法:

//读取一个字节并以整数的形式返回(0~255)  
// 如果返回-1就说明已经到了输入流的末尾  
int read () throws IOException  
  
//读取一系列字节并存储到一个数组buffer  
// 返回实际读取的字节数,如果读取前已到输入流的末尾,则返回-1  
int read ( byte[] buffer) throws IOException  
  
//从offset位置开始,读取length个字节,并存储到一个字节数组buffer,  
// 返回实际读取的字节数,如果读取前以到输入流的末尾返回-1.  
int read ( byte[] buffer, int offset, int length) throws IOException  
  
//关闭流释放内存资源  
void close () throws IOException  
  
//跳过n个字节不读,返回实际跳过的字节数  
long skip(long n) throws IOException

OutputStream 的常用方法:

//向输出流中写入一个字节数据,该字节数据为参数b的低8位
void write(int b) throws IoException

//将一个字节类型的数组中的数据写入输出流
void write(byte[] b)throws IoException

//将一个字节类型的数组中的从指定位置(off)开始的1en个字节写入到输出流
void write(byte[] b,int off,int len)throws IoException

//关闭流释放内存资源
void close() throws IoException

//将输出流中缓冲的数据全部写出到目的地
void flush() throws IoException

4.3 InputStream和OutputStream的子类

InputStream的子类:



OutputStream的子类:



4.4 常见流操作

一、基类流

其实始终有人搞不清楚到底InputStream是读还是OutputStream是读。其实很简单就可以记住,你把你自己想象为是一个程序,InputStream对你来说是输入,也就是你要从某个地方读到自己这来,而OutputStream对你来说就是输出,也就是说你需要写到某个地方。这样就可以简单的区分输入输出流。下面看看InputStream的成员方法:

public abstract int read() throws IOException;

public int read(byte b[]) throws IOException
 
public int read(byte b[], int off, int len)

public long skip(long n) throws IOException

public int available() throws IOException

public void close() throws IOException

public synchronized void mark(int readlimit)
public synchronized void reset() throws IOException
public boolean markSupported()

InputStream是一个输入流,也就是用来读取文件的流,抽象方法read读取下一个字节,当读取到文件的末尾时候返回 -1。如果流中没有数据read就会阻塞直至数据到来或者异常出现或者流关闭。这是一个受查异常,具体的调用者必须处理异常。除了一次读取一个字节,InputStream中还提供了`read(byte[])`,读取多个字节。`read(byte[])`其实默认调用的还是`read(byte b[], int off, int len)`方法,表示每读取一个字节就放在b[off++]中,总共读取len个字节,但是往往会出现流中字节数小于len,所以返回的是实际读取到的字节数。


接下来是一些高级的用法,skip方法表示跳过指定的字节数,来读取。调用这种方法需要知道,一旦跳过就不能返回到原来的位置。当然,我们可以看到还有剩下的三种方法,他们一起合作实现了可重复读的操作。mark方法在指定的位置打上标记,reset方法可以重新回到之前的标记索引处。但是我们可以想到,它一定是在打下mark标记的地方,使用字节数组记录下接下来的路径上的所有字节数据,直到你使用了reset方法,取出字节数组中的数据供你读取(实际上也不是一种能够重复读,只是用字节数组记录下这一路上的数据而已,等到你想要回去的时候将字节数组给你重新读取)。


OutputStream是一种输出流,具体的方法和InputStream差不多,只是,一个读一个写。但是,他们都是抽象类,想要实现具体的功能还是需要依赖他们的子类来实现,例如:FileInputStream/FileOutputStream等。

二、文件字节流

FileInputStream继承与InputStream,主要有以下两个构造方法:

 public FileInputStream(String name)
 
 public FileInputStream(File file)

第一种构造方法传的是一个字符串,实际上是一个确定文件的路径,内部将此路径封装成File类型,调用第二种构造方法。第二中构造方法,直接绑定的是一个具体的文件。 FileInputStream 的内部方法其实和父类InputStream中定义的方法差不多,我们通过一个读文件的实例来演示用法。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{
            FileInputStream fin = new FileInputStream("hello.txt");
            byte[] buffer = new byte[1024];
            int x = fin.read(buffer,0,buffer.length);
            String str = new String(buffer);
            System.out.println(str);
            System.out.println(x);
            fin.close();
    }
}
输出结果:
hello world
13

结果意料之中,调用了read方法将hello.txt中的内容读到字节数组buffer中,然后通过String类构造方法将字节数组转换成字符串。返回实际上读取到的字节数13。(10个字母+两个空格+一个字符串结束符) FileOutputStream继承父类OutputStream,主要方法代码如下:

private final boolean append;

public FileOutputStream(String name)
public FileOutputStream(String name, boolean append)
public FileOutputStream(File file)
public FileOutputStream(File file, boolean append)

private native void writeBytes(byte b[], int off, int len, boolean append)
public void write(byte b[]) throws IOException

FileOutputStream的一些基本的操作和FileInputStream类似,只是一个是读一个是写。我们主要要知道,append属性是指定对于文件的操作是覆盖方式(false),还是追加方式(true)。下面通过一个实例演示其用法:

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{
        FileOutputStream fou = new FileOutputStream("hello.txt");
        String str = "Walker_YAM";
        byte[] buffer = str.getBytes("UTF-8");
        fou.write(buffer,0 ,buffer.length);
        fou.close();
    }
}

如我们所料,字符串"Walker_YAM"将会被写入hello.txt,由于没有指定append,所以将会覆盖hello.txt中的所有内容。

三、动态字节数组流

在我们上述的文件读取流中,我们定义 byte[] buffer = new byte[1024];,buffer数组为1024,如果我们将要读取的文件中的内容有1025个字节,buffer是不是装不下?当然我们也可以定义更大的数组容量,但是从内存的使用效率上,这是低效的。我们可以使用动态的字节数组流来提高效率。 ByteArrayInputStream的内部使用了类似于ArrayList的动态数组扩容的思想。

protected byte buf[];
protected int count;

public ByteArrayInputStream(byte buf[])
public ByteArrayInputStream(byte buf[], int offset, int length)
public synchronized int read()
public synchronized int read(byte b[], int off, int len)

ByteArrayInputStream内部定义了一个buf数组和记录数组中实际的字节数,read方法也很简单,读取下一个字节,read(byte b[], int off, int len) 将内置字节数组读入目标数组。实际上,整个ByteArrayInputStream也就是将一个字节数组封装在其内部。为什么这么做?主要还是为了方便参与整个InputStream的体系,复用代码。 ByteArrayOutputStream的作用要比ByteArrayInputStream更加的实际一点:

protected byte buf[];
protected int count;

public ByteArrayOutputStream() {
        this(32);
    }
public ByteArrayOutputStream(int size)
private void ensureCapacity(int minCapacity)
public synchronized void write(byte b[], int off, int len)
public synchronized void writeTo(OutputStream out)
public synchronized byte toByteArray()[]
public synchronized String toString()

和ByteArrayInputStream一样,内部依然封装了字节数组buf和实际容量count,通过构造方法可以指定内置字节数组的长度。主要的是write方法,将外部传入的字节数组写到内置数组中,writeTo方法可以理解为将自己内置的数组交给OutputStream 的其他子类使用。toByteArray和toString则会将内置数组转换成指定类型返回。 下面我们利用他们来解决刚开始说的效率问题。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{
        FileInputStream fin = new FileInputStream("hello.txt");
        ByteArrayOutputStream bou = new ByteArrayOutputStream();
        int x = 0;
        while((x = fin.read()) !=-1){
                bou.write(x);
        }
        System.out.println(bou.toString());
    }
}

从hello文件中每读取一个字节写入ByteArrayOutputStream 中,我们不用担心hello文件太大而需要设置较大的数组,使用ByteArrayOutputStream 动态增加容量,如果添加字节即将超过容量上限,进行扩充(往往是指数级扩充)

四、装饰者字节流 上述的流都是直接通过操作字节数组来实现输入输出的,那如果我们想要输入一个字符串类型或者int型或者double类型,那还需要调用各自的转字节数组的方法,然后将字节数组输入到流中。我们可以使用装饰流,帮我们完成转换的操作。我们先看DataOutputStream。

 public DataOutputStream(OutputStream out)
 public synchronized void write(byte b[], int off, int len)
 public final void writeBoolean(boolean v)
 public final void writeByte(int v)
 public final void writeShort(int v)
 public final void writeInt(int v) 
 public final void writeDouble(double v)

简单的列举了一些方法,可以看到,DataOutputStream只有一个构造方法,必须传入一个OutputStream类型参数。(其实它的内部还是围绕着OutputStream,只是在它的基础上做了些封装)。我们看到,有writeBoolean、writeByte、writeShort、writeDouble等方法。他们内部都是将传入的 boolean,Byte,short,double类型变量转换为了字节数组,然后调用从构造方法中接入的OutputStream参数的write方法。

//这是writeInt的具体实现
    public final void writeInt(int v) throws IOException {
        out.write((v >>> 24) & 0xFF);
        out.write((v >>> 16) & 0xFF);
        out.write((v >>>  8) & 0xFF);
        out.write((v >>>  0) & 0xFF);
        incCount(4);
    }

将一个四个字节的int类型,分开写入,先写入高八位。总共写四次,第一次将高八位移动到低八位与上0xFF获得整个int的低八位,这样就完成了将原高八位写入的操作,后续操作类似。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{
        DataOutputStream da = new DataOutputStream(new FileOutputStream("hello.txt"));
        da.writeInt(11);
        da.close();
    }
}

五、缓冲流

在这之前,我们读取一个字节就要将它写会磁盘,这样来回开销很大,我们可以使用缓冲区来提高效率,在缓冲区满的时候,或者流关闭时候,将缓冲区中所有的内容全部写会磁盘。BufferedInputStream和BufferedOutputStream也是一对装饰流,我们先看看BufferedInputStream:

private static int DEFAULT_BUFFER_SIZE = 8192;
protected volatile byte buf[];
protected int pos;
protected int count;
public BufferedInputStream(InputStream in)
public BufferedInputStream(InputStream in, int size)
public synchronized int read()
public synchronized void mark(int readlimit)
public synchronized void reset()

一样也是装饰类流,第一种构造方法要求必须传入InputStream类型参数,DEFAULT_BUFFER_SIZE 指定了默认的缓冲区的大小,当然还可以使用第二种构造方法指定缓冲区的大小(当然不能超过上界),read方法读取的时候会将数据读入内部的缓冲区中,当然缓冲区也是可以动态扩容的。

public class Test_InputOrOutput {
    public static void main(String[] args) throws IOException{
        BufferedInputStream bi = new BufferedInputStream(new FileInputStream("hello.txt"));
        bi.read();
        bi.read();
        bi.read();
        bi.read();
        System.out.println(bi.available());
    }
}

BufferedOutputStream和它是逆操作,不在赘述。这种缓冲字节流可以很大程度上提高我们的程序执行的效率,所以一般在使用别的流的时候都会包装上这层缓冲流。

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码