初识Java 15-1 文件

news2024/11/17 6:39:44

目录

文件和目录路径

选择Path的片段

分析Path

添加或删除路径片段

目录

文件系统

监听Path

查找文件

读写文件


本笔记参考自: 《On Java 中文版》

更多详细内容请查看官方文档。


        Java 7优化了Java的I/O编程,具体的表现就是java.nio.file。其中,nio中的n原本表示“new”,现在则是指代“non-blocking”(非阻塞)。在此之后的Java 8还新增了流,因此现在可以较为轻松地使用Java的文件编程。

文件和目录路径

        Path对象表示的是一个文件或目录的路径,它是在不同操作系统和文件系统之上的抽象

这一对象存在的目的是,让我们在构建路径时不必在意底层的操作系统。换言之,我们的代码无须重写就能在不同的操作系统上运行。

        在开始第一个示例之前,需要先介绍static get方法,它在java.nio.file.Paths类中进行了重载:

现在它能够接受一个String,或是一个URL(统一资源标志符),并将其转换为一个Path对象。

【例子:查看文件的信息】

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;

public class PathInfo {
    static void show(String id, Object p) {
        System.out.println(id + p);
    }

    static void info(Path p) {
        show("显示文件路径(toString):", p);
        show("路径指向文件是否存在:", Files.exists(p));
        show("路径指向文件是否是常规文件:", Files.isRegularFile(p));
        show("路径是否指向目录:", Files.isDirectory(p));
        show("判断该路径是否为绝对路径:", p.isAbsolute());
        show("返回路径指向文件的名字:", p.getFileName());
        show("返回父路径(若路径不存在,返回null):", p.getParent());
        show("当前路径的根:", p.getRoot());
        System.out.println("=========================");
    }

    public static void main(String[] args) {
        System.out.println(System.getProperty("os.name")); // 显示操作系统的名称

        info(Path.of(
                "./", "path", "to", "nowhere", "该文件不存在.txt"));

        Path p = Path.of("PathInfo.java");
        info(p);

        Path ap = p.toAbsolutePath(); // 返回绝对路径
        info(ap);
        info(ap.getParent());

        try {
            info(p.toRealPath()); // 返回p的实际路径
        } catch (IOException e) {
            System.out.println(e);
        }

        URI u = p.toUri();
        System.out.println("URI: " + u);
        Path puri = Path.of(u);
        System.out.println(Files.exists(puri));
        File f = ap.toFile(); // 注意:toFile生成的File对象表示的是一个文件,或者是目录
    }
}

        程序执行的结果是:

        “该文件不存在.txt”表示,我们可以描述一个不存在的文件,这就允许我们创建一条新的路径。

        在上述的show()方法中,存在一条用来描述实际路径的语句。实际上,文档中对实际路径的定义较为模糊,因为这一路径取决于特定的文件系统。

        最后是toFile(),这一方法的存在是为了向后兼容。它表示的是文件或者目录(就像Path)。

选择Path的片段

        可以使用方法获取Path对象路径的各个部分:

【例子:获取Path的片段】

import java.nio.file.Path;

public class PartsOfPaths {
    public static void main(String[] args) {
        System.out.println(System.getProperty("os.name"));

        System.out.println();
        Path p = Path.of("PartsOfPaths.java").toAbsolutePath();
        for (int i = 0; i < p.getNameCount(); i++)
            System.out.println(p.getName(i));
        System.out.println("此路径是否以【.java】结尾:" + p.endsWith(".java"));

        System.out.println();
        for (Path pp : p) {
            System.out.println("当前路径是否以【"+pp+"】为开始:"+p.startsWith(pp));
            System.out.println("当前路径是否以【"+pp+"】结尾:"+p.endsWith(pp));
            System.out.println("---------------");
        }

        System.out.println("是否以【" + p.getRoot() +
                "】作为路径起点:" + p.startsWith(p.getRoot()));
    }
}

        程序执行的结果是:

        因为Path可以生成Iterator,因此我们可以使用for-in来遍历整个Path。这里有一个问题,尽管路径确实以.java结尾,但是endsWith()方法的结果依旧是false。这是因为endsWith()会比较整个路径组件,而不是路径中单一的子串,for-in循环验证了这一点。

    另外,当我们对Path进行遍历时,并没有包含根目录。当我们使用startsWith()检查根目录时,我们获得了true


分析Path

        files工具包中存在许多用来检查Path信息的方法:

【例子:检查Path的信息】

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;

public class PathAnalysis {
    static void say(String id, Object result) {
        System.out.print(id + ": ");
        System.out.println(result);
    }

    public static void main(String[] args)
            throws IOException {
        System.out.println(System.getProperty("os.name"));

        System.out.println();
        Path p =
                Path.of("PathAnalysis.java").toAbsolutePath();

        say("是否存在", Files.exists(p));
        say("是否是一个目录:", Files.isDirectory(p));
        say("是否是一个常规文件", Files.isRegularFile(p));
        say("是否可执行:", Files.isExecutable(p));
        say("是否可读:", Files.isReadable(p));
        say("是否可写", Files.isWritable(p));
        say("按当前路径定位的文件是否存在:", Files.notExists(p));
        say("是否是被隐藏的:", Files.isHidden(p));
        say("文件的大小(以字节为单位):", Files.size(p));
        say("文件所在存储区的FileStore(卷):", Files.getFileStore(p));
        say("文件上次修改的时间:", Files.getLastModifiedTime(p));
        say("文件的所有者:", Files.getOwner(p));
        say("文件的内容类型:", Files.probeContentType(p));

        say("是否是一个符号链接:", Files.isSymbolicLink(p));
        if (Files.isSymbolicLink(p))
            say("读取当前符号链接:", Files.readSymbolicLink(p));
        if (FileSystems.getDefault()
                .supportedFileAttributeViews().contains("posix"))
            say("文件的POSIX文件权限:", Files.getPosixFilePermissions(p));
    }
}

        程序执行的结果是:

        最后一项测试,若系统不支持Posix,会得到一个运行时异常。


添加或删除路径片段

        Java允许我们通过对Path对象进行路径片段的增删来构建Path对象。对应增删的有两个方法:

  • relativize():可用来删除基准路径,基准路径由使用者自己决定(只有当Path是绝对路径时,才能作为该方法的参数)。
  • resolve():可用来增加路径片段。

【例子:Path的增删】

import java.io.IOException;
import java.nio.file.Path;

public class AddAndSubtractPaths {
    // 自定义基准路径
    static Path base = Path.of("..", "..", "..")
            .toAbsolutePath()
            .normalize(); // 消除路径中的冗余元素

    static void show(int id, Path result) {
        if (result.isAbsolute())
            System.out.println("绝对路径(" + id + ") "
                    + base.relativize(result));
        else
            System.out.println("(" + id + ") " + result);

        try {
            System.out.println("实际路径:" + result.toRealPath());
        } catch (IOException e) {
            System.out.println(e);
        }
        System.out.println("-------------");
    }

    public static void main(String[] args) {
        System.out.println(System.getProperty("os.name"));

        System.out.println();
        System.out.println("base: " + base);
        Path p = Path.of("AddAndSubtractPaths.java")
                .toAbsolutePath();
        show(1, p);

        Path convoluted = p
                .getParent()
                .getParent()
                .resolve("strings")
                .resolve("..")
                .resolve(p.getParent().getFileName());
        show(2, convoluted);

        show(3, convoluted.normalize());

        Path p2 = Path.of("..", "..");
        show(4, p2);
        show(5, p2.normalize());
        show(6, p2.toAbsolutePath().normalize());

        Path p3 = Path.of(".").toAbsolutePath();
        Path p4 = p3.resolve(p2);
        show(7, p4);
        show(8, p4.normalize());

        Path p5 = Path.of("").toAbsolutePath();
        show(9, p5);
        show(10, p5.resolveSibling("strings"));
        show(11, Path.of("不存在的路径"));
    }
}

        程序执行的结果是:

目录

        Files工具类包含了操作目录和文件的大部分操作。但遗憾的是,其中并没有用于删除目录树的工具。下面是一个删除目录树的例子:

【例子:删除目录树】

package onjava;

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

public class Rmdir {
    public static void rmdir(Path dir)
            throws IOException {
        Files.walkFileTree(dir, // 遍历目录树
                // 访问目录中的文件
                new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult visitFile(Path file,
                                                     BasicFileAttributes attrs)
                            throws IOException {
                        Files.delete(file); // 删除文件
                        return FileVisitResult.CONTINUE;
                    }

                    // 该方法在访问了目录的所有条目后调用
                    @Override
                    public FileVisitResult postVisitDirectory(Path dir,
                                                              IOException exc)
                            throws IOException {
                        Files.delete(dir); // 删除目录
                        return FileVisitResult.CONTINUE;
                    }
                });
    }
}

        walkFileTree的意思是查找每个子目录和文件,也就是遍历。

这种访问者的设计模式提供了一个访问集合中的每个对象的标准机制,它要求我们提供需要在每个对象上执行的动作。而这一动作又取决于我们如何实现FileVisitor

        FileVisitor接口包含了以下方法:

  • preVisitDirectory():先处理当前目录,再进入这个目录下的文件和目录中。
  • visitFile():在这个目录下的每个文件上运行。
  • visitFileFailed():当文件无法访问时调用。
  • postVisitDirectory():先进入这个目录下的文件和目录中(包括子目录),最后处理当前目录。

        java.nio.file.SimpleFileVisitor为所有这些方法提供了默认的定义。上述例子仅仅简单(而不规范)地重写了这些方法。

        下面的例子会根据一个基准目录test,通过旋转parts生成不同的子目录路径:

【例子:生成子目录】

import onjava.RmDir;

import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Directories {
    static Path test = Path.of("test"); // 生成一个基准目录test的Path对象
    static String sep = // 获取默认文件系统的分隔符(在Windows中,就是【/】)
            FileSystems.getDefault().getSeparator();

    static List<String> parts =
            Arrays.asList("foo", "bar", "baz", "bag");

    static Path makeVariant() {
        Collections.rotate(parts, 1); // 将parts中的元素进行旋转
        return Path.of("test", String.join(sep, parts)); // 通过分隔符sep连接parts中的元素,形成字符串
    }

    static void refreshTestDir()
            throws Exception {
        if (Files.exists(test)) // 若文件存在
            RmDir.rmdir(test);
        if (!Files.exists(test)) // 再次检查
            Files.createDirectory(test);
    }

    public static void main(String[] args)
            throws Exception { 
        refreshTestDir(); // 检测test是否已经存在
        Files.createFile(test.resolve("Hello.txt")); // 根据路径创建一个文件
        Path variant = makeVariant();

        try {
            Files.createDirectory(variant); // 只能用于创建单层目录
        } catch (Exception e) {
            System.out.println("无法正常工作(目录层次太多)");
        }

        populateTestDir();

        Path tempdir =
                Files.createTempDirectory(test, "DIR_"); // 使用给定前缀创建目录
        Files.createTempFile(tempdir, "pre", ".non"); // 使用给定的前缀和后缀生成文件
        Files.newDirectoryStream(test) // 一个流,用以迭代目录中的所有条目
                .forEach(System.out::println);
        System.out.println("============");

        Files.walk(test) // 遍历目录树
                .forEach(System.out::println);
    }

    static void populateTestDir()
            throws Exception {
        for (int i = 0; i < parts.size(); i++) {
            Path variant = makeVariant();
            if (!Files.exists(variant)) {
                Files.createDirectories(variant); // 与createDirectory的不同之处在于,不会因为目录已经存在而抛出异常
                Files.copy(Path.of("Directories.java"),
                        variant.resolve("File.txt")); // 将Directories.java的内容复制到File.txt中
                Files.createTempFile(variant, null, null); // 在临时目录中创建一个空文件
            }
        }
    }
}

        程序执行的结果是:

        若一个目录已经存在,此时调用createDirectory()将会产生异常。因此在创建目录之前最好检查一下。另外,该方法只能用于创建单层目录,所以当我们传入一个包含许多层次的variant时,我们捕获了异常。

        再说一下newDirectoryStream()walk()的区别,这两者都会生成一个关于目录的流。但从结果就可以看出,newDirectoryStream()中只有test目录下的内容,并没有进入目录内部,而walk()可以做到这点。

文件系统

        获取文件系统信息的方式有3种:

  • 通过FileSystems工具来获取“默认”的文件系统信息。
  • 通过Path对象的getFileSystem()来获取创建这个路径对象的文件系统的信息。

        另外,我们还可以通过给定的URI获得或构建一个文件系统。

【例子:获取文件系统的信息】

import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;

public class FileStstemDemo {
    static void show(String id, Object o) {
        System.out.println(id + ": " + o);
    }

    public static void main(String[] args) {
        System.out.println(System.getProperty("os.name"));

        System.out.println();
        FileSystem fsys = FileSystems.getDefault(); // 获取默认的文件系统
        for (FileStore fs : fsys.getFileStores()) // 获取底层(即硬盘上的)文件存储流
            show("文件存储", fs);
        for (Path rd : fsys.getRootDirectories()) // 获取根目录的流
            show("根目录的路径", rd);
        show("名称分隔符", fsys.getSeparator());

        System.out.println();
        show("此系统的UserPrincipalLookupService",
                fsys.getUserPrincipalLookupService());
        show("此文件系统是否打开", fsys.isOpen());
        show("此文件存储区是否是只读访问", fsys.isReadOnly());
        show("创建此文件系统的提供程序", fsys.provider());
        show("此文件系统支持的文件属性视图", fsys.supportedFileAttributeViews());
    }
}

        程序执行的结果是(由于Linux的文件存储过长,故不做展示)

监听Path

        FileSystem还提供了WatchService,通过它我们能够监听目录的变化。

【例子:监听一个目录】

import java.io.IOException;
import java.nio.file.*;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static java.nio.file.StandardWatchEventKinds.*;

public class PathWatcher {
    static Path test = Path.of("test");

    static void delTxtFiles() {
        try {
            Files.walk(test)
                    .filter(f -> // 删除所有以.txt结尾的文件
                            f.toString().endsWith(".txt"))
                    .forEach(f -> {
                        try {
                            System.out.println("正在删除:" + f);
                            Files.delete(f);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    });
        } catch (IOException e) { // 因为一些原因,Java会要求我们在内部和外部都捕获异常
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args)
            throws Exception {
        Directories.refreshTestDir(); // 创建目录
        Directories.populateTestDir();
        Files.createFile(test.resolve("Hello.txt"));

        WatchService watcher =
                FileSystems.getDefault().newWatchService(); // 创建一个新的监听
        test.register(watcher, ENTRY_DELETE); // 向监听服务watcher注册test,监听删除行为

        // 创建一个单线程执行器,在给定时延后运行delTxtFiles
        Executors.newSingleThreadScheduledExecutor()
                .schedule(
                        PathWatcher::delTxtFiles,
                        250, TimeUnit.MILLISECONDS);

        WatchKey key = watcher.take(); //检索、删除(并返回)下一个监听标识
        // 将监听的事件逐个打印
        for (WatchEvent evt : key.pollEvents()) {
            System.out.println(
                    "事件所处上下文: " + evt.context() +
                            "\n事件计数: " + evt.count() +
                            "\n事件类型: " + evt.kind());
            System.exit(0);
        }
    }
}

        程序执行的结果是:

        在delTxtFiles()中,需要显式地调用f.toString(),否则endWith()会比较整个Path对象,而不是用其字符串表示的名字部分。

        FileSystem创建了一个WatchSerive:

可以将需要监听的事件(将其组成参数列表)传输给test.register()进行注册。可以注册三种事件:

  • 创建:ENTRY_CREATE
  • 删除:ENTRY_DELETE
  • 修改:ENTRY_MODIFY

(注意,删除和创建并不算做修改)

        当我们使用watcher.take()进行监听时,程序会停留在这里等待知道预订的事件出现(串行执行)。此时若没有外力介入删除其监听的文件,程序就不会继续执行。因此,我们需要并行执行delTxtFiles()

通过这条语句,我们设置了一个执行器。schedule()操作允许我们指定方法,在给定时间后执行它。此时我们调用watch.take(),主线程会等待,直到删除操作发生。

        注意:WatchService只会监听当前目录,这意味着就算这个目录存在子目录,其中发生的任何事也不会被该WatchService中监听。

        因此,若想要监听整个目录树,就必须为所有的子目录都设置一个WatchSerive

【例子:监听整个目录树】

import java.io.IOException;
import java.nio.file.*;
import java.util.concurrent.Executors;

import static java.nio.file.StandardWatchEventKinds.*;

public class TreeWatcher {
    static void watchDir(Path dir) {
        try {
            WatchService watcher =
                    FileSystems.getDefault().newWatchService();
            dir.register(watcher, ENTRY_DELETE);
            Executors.newSingleThreadScheduledExecutor().submit(() -> { // 直接运行任务
                try {
                    WatchKey key = watcher.take();
                    for (WatchEvent evt : key.pollEvents()) {
                        System.out.println(
                                "事件所处上下文: " + evt.context() +
                                        "\n事件计数: " + evt.count() +
                                        "\n事件类型: " + evt.kind());
                        System.exit(0);
                    }
                } catch (InterruptedException e) {
                    return;
                }
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args)
            throws Exception {
        Directories.refreshTestDir();
        Directories.populateTestDir();
        Files.walk(Path.of("test"))
                .filter(Files::isDirectory)
                .forEach(TreeWatcher::watchDir);
        PathWatcher.delTxtFiles();
    }
}

        程序执行的结果是:

        这次我们为每一个进程单独设置了一个WatchService。并且没有推迟任务运行,而是通过submit()操作让任务即刻生效。

查找文件

        在此之前,我们使用PathtoString()String的操作来查看结果。但java.nio.file提供了一个更好的方案:PathMatcherFileSystem对象有一个getPathMatcher(),通过它我们能获取一个PathMatcher

从图片的描述中可以发现,这个方法有一个参数,我们能够选择一个模式并且传给它。模式的两个选项分别为globregex,这里会展示前者的用法。

        下面的例子会通过使用glob来查找所有文件以.tmp.txt结尾的Path

【例子:使用getPathMatcher

import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;

public class Find {
    public static void main(String[] args)
            throws Exception {
        Path test = Path.of("test");
        Directories.refreshTestDir();
        Directories.populateTestDir();
        // 创建一个目录(而不是文件):
        Files.createDirectory(test.resolve("dir.tmp"));

        PathMatcher matcher1 = FileSystems.getDefault()
                .getPathMatcher("glob:**/*.{tmp,txt}"); // 匹配目录树中,所有以.tmp或.txt结尾的文件
        Files.walk(test)
                .filter(matcher1::matches) // 匹配成功则进行打印
                .forEach(System.out::println);
        System.out.println("==============");

        PathMatcher matcher2 = FileSystems.getDefault()
                .getPathMatcher("glob:*.tmp");
        Files.walk(test)
                .map(Path::getFileName) // 使用map()操作将路径缩减至最后的名字
                .filter(matcher2::matches)
                .forEach(System.out::println);
        System.out.println("==============");

        Files.walk(test)
                .filter(Files::isRegularFile)
                .map(Path::getFileName)
                .filter(matcher2::matches)
                .forEach(System.out::println);
    }
}

        程序执行的结果是:

        介绍一下glob表达式。在使用glob时,可以使用类似于正则表达式的语言进行匹配(此处根据上述例子进行简单介绍,若需要详细了解,可前往官方文档):

规则(字符)解释
*匹配任何名称,但不会跨越目录边界(不会进入子目录)。
**匹配零个或多个字符(例如:**/代表“所有子目录”)。
?和正则表达式中的类似,可以完全匹配一个字符。
/用于转义。
[ ]将一组字符与名称中的单个字符进行匹配。
{ }内部是一组子模式。每次从中取出一个子串进行匹配(子串之间用【 , 】进行分隔)。

         注意:在第一次和第二次的walk()中,我们都看到了dir.tmp,尽管它是一个文件(而非目录)。若只需要文件,那么应该像最后一次的walk()那样进行过滤。

读写文件

        java.nio.file.Files类包含了方便读写文本文件和二进制文件的工具函数。

        若一个文件是较小的(内存中放得下),那么我们可以使用Files.readAllLines()一次性读入整个文件,并且生成一个List<String>

【例子:读取文件】

        设置一个需要读取的文件Cheese.dat(假设它被放在data文件夹中):

        对其进行读取:

// 位于files文件夹中,files文件夹和data文件夹处于同一目录中
import java.nio.file.Files;
import java.nio.file.Path;

public class ListOfLines {
    public static void main(String[] args)
            throws Exception {
        Files.readAllLines(
                Path.of("../data/Cheese.dat"))
                .stream()
                .filter(line -> !line.startsWith("//"))
                .map(line -> line.substring(0, line.length() / 2))
                .forEach(System.out::println);
    }
}

        程序执行的结果是:

        注释行被跳过了,并且其他行只被打印了一半。

    readAllLines()还有一个重载的版本,包含一个Charset参数,用于确定文件的Unicode编码。

        除此之外,还可以使用Files.write()的重载方法。这些重载支持byte数组或任何实现了Iterable接口的类的对象。

【例子:写入数组或对象】

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Random;

public class Writing {
    static Random rand = new Random(47);
    static final int SIZE = 1000;

    public static void main(String[] args)
            throws Exception {
        // 将字节写入一个文件:
        byte[] bytes = new byte[SIZE];
        rand.nextBytes(bytes);
        Files.write(Path.of("bytes.dat"), bytes);
        System.out.println("bytes.dat: " +
                Files.size(Path.of("bytes.dat")));

        // 将实现了Iterable接口的类的对象写入文件:
        List<String> lines = Files.readAllLines(
                Path.of("../data/Cheese.dat"));
        Files.write(Path.of("Cheese.txt"), lines);
        System.out.println("Cheese.txt: " +
                Files.size(Path.of("Cheese.txt")));
    }
}

        程序执行的结果是:

        目录中已经出现我们创建的文件了:

        这里,我们需要提出一个疑问:如果文件太大了怎么办?一个好的办法是每次只使用文件的一部分,这时候就需要使用到流了。

        Files.lines()可以将一个文件转变成一个由行组成的流

 【例子:文件的输入流】

import java.nio.file.Files;
import java.nio.file.Path;

public class ReadLineStream {
    public static void main(String[] args)
            throws Exception {
        Files.lines(Path.of("PathInfo.java")) // 指定一个文件
                .skip(13) // 跳过13行
                .findFirst()
                .ifPresent(System.out::println);
    }
}

        程序执行的结果是:

        上述程序完成了一个输入流,而下面的例子会展示在流中进行读取、处理和写入的过程:

【例子:使用流处理文件】

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;

public class StreamInAndOut {
    public static void main(String[] args) {
        try (
                Stream<String> input =
                        Files.lines(Path.of("StreamInAndOut.java"));
                PrintWriter output = // 指定输出流
                        new PrintWriter("StreamInAndOut.txt");
        ) {
            input.map(String::toUpperCase)
                    .forEachOrdered(output::println);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

        PrintWriter来自于java.io类,用于向指定文件打印信息。可以观察StreamInAndOut.txt

所有内容确实转变为了大写形式。

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

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

相关文章

【王道代码】【2.3链表】d3

关键字&#xff1a; 奇偶序号拆分、a1&#xff0c;b1&#xff0c;a2&#xff0c;b2...an&#xff0c;bn拆分a1&#xff0c;a2...&#xff0c;bn&#xff0c;...b2&#xff0c;b1、删除相同元素

以人物画像谈测试员如何半道介入一个新项目

最近在带新人了解项目&#xff0c;这已经不是第一次带新人&#xff0c;由此引发了我关于新进项目的测试人员如何能够快速介入一个新项目的思考。这里我特指的是项目已经运行一段周期&#xff0c;新进员工或其他项目测试人员中途进入该项目的情况。对于项目一启动&#xff0c;测…

Apache Doris (四十六): Doris数据更新与删除 - 批量删除

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录

分享一个python无人超市管理系统django项目实战源码调试 lw 开题

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

文件存储空间管理(空闲表法,空闲链表法,位示图法,成组链表法)

1.存储空间的划分与初始化 1.文件卷&#xff08;逻辑卷)的概念 存储空间的划分:将物理磁盘划分为一个个文件卷&#xff08;逻辑卷、逻辑盘). 2.目录区与文件区 存储空间的初始化&#xff1a;将各个文件卷划分为目录区、文件区。 目录区包含文件目录、空闲表、位示图、超级…

嵌入式养成计划-46----QT--简易版网络聊天室实现--QT如何连接数据库

一百一十九、简易版网络聊天室实现 119.1 QT实现连接TCP协议 119.1.1 基于TCP的通信流程 119.1.2 QT中实现服务器过程 使用QTcpServer实例化一个服务器对象设置监听状态&#xff0c;通过listen()函数&#xff0c;可以监听特定的主机&#xff0c;也可以监听所有客户端&#x…

Unity读取写入Excel

1.在Plugins中放入dll&#xff0c;118开头的dll在Unity安装目录下&#xff08;C:\Program Files\Unity\Editor\Data\Mono\lib\mono\unity&#xff09; 2.写Excel public void WriteExcel(){//文件地址FileInfo newFile new FileInfo(Application.dataPath "/test.xlsx…

v-on 可以监听多个方法吗?

目录 ​编辑 前言&#xff1a;Vue 3 中的 v-on 指令 详解&#xff1a;v-on 指令的基本概念 用法&#xff1a;v-on 指令监听多个方法 解析&#xff1a;v-on 指令的优势和局限性 优势 局限性 **v-on 指令的最佳实践** - **适度监听**&#xff1a; - **方法抽离**&#x…

【并发编程】多线程读写同一变量的并发问题(并发编程启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

《动手学深度学习 Pytorch版》 10.1 注意力提示

10.1.1 生物学中的注意力提示 “美国心理学之父” 威廉詹姆斯提出的双组件&#xff08;two-component&#xff09;框架&#xff1a; 非自主性提示&#xff1a;基于环境中物体的突出性和易见性 自主性提示&#xff1a;受到了认知和意识的控制 10.1.2 查询、键和值 注意力机制…

一款功能强大的音乐曲谱软件Guitar Pro 8 .1.1for Mac 中文破解版

Guitar Pro 8 .1.1for Mac 中文破解版是一款功能强大的音乐曲谱软件&#xff0c;非常适合学习如何玩&#xff0c;改进技巧&#xff0c;重现喜爱的歌曲或陪伴自己。可以帮助我们进行吉他的学习、绘谱与创作&#xff0c;它包含了几乎所有的吉他现有指法及音色&#xff0c;在做弹拨…

C语言求 3*3 矩阵对角线之和

完整代码&#xff1a; // 求 3*3 矩阵对角线之和 #include<stdio.h>int main() {int n3;int arr[3][3];// 输入矩阵printf("请输入矩阵的元素:\n");for (int i 0; i < n; i){for (int j 0; j < n; j){scanf("%d", &arr[i][j]);}}int su…

OpenCV官方教程中文版 —— 图像金字塔

OpenCV官方教程中文版 —— 图像金字塔 前言一、原理二、使用金字塔进行图像融合 前言 • 学习图像金字塔 • 使用图像创建一个新水果&#xff1a;“橘子苹果” • 将要学习的函数有&#xff1a;cv2.pyrUp()&#xff0c;cv2.pyrDown()。 一、原理 一般情况下&#xff0c;我…

【Ubuntu18.04】激光雷达与相机联合标定(Livox+HIKROBOT)(一)

LivoxHIKROBOT联合标定 引言1 海康机器人HIKROBOT SDK二次开发并封装ROS1.1 介绍1.2 安装MVS SDK1.3 封装ROS packge 2 览沃Livox SDK二次开发并封装ROS3 相机雷达联合标定3.1 环境配置3.1.1 安装依赖——PCL 安装3.1.2 安装依赖——Eigen 安装3.1.3 安装依赖——Ceres-solver …

计算机视觉-数学基础*变换域表示

被研究最多的图像&#xff08;或任何序列数据&#xff09;变换域表示是通过傅 里叶分析 。所谓的傅里叶表示就是使用 正弦函数的线性组合来表示信号。对于一个给定的图像I(n1,n2) &#xff0c;可以用如下方式分解它&#xff08;即逆傅里叶变换&#xff09;&#xff1a; 其中&a…

浅谈APP自动化测试工具主要优势

移动应用程序已经成为我们日常生活和商业活动的重要组成部分。随着用户对应用性能、稳定性和用户体验的需求不断增加&#xff0c;开发人员不得不寻找方法来确保他们的应用在各种情况下都能正常运行。这就引入了自动化测试工具&#xff0c;这些工具通过自动执行测试用例来检查应…

openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立

文章目录 openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立107.1 默认的用户权限107.2 三权分立较非三权分立权限变化说明 openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立 默认权限机制和管理员两节的描述基于的是openGauss创建之初…

2023-10-23 LeetCode每日一题(老人的数目)

2023-10-23每日一题 一、题目编号 2678. 老人的数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的字符串 details 。details 中每个元素都是一位乘客的信息&#xff0c;信息用长度为 15 的字符串表示&#xff0c;表示方式如下&#xff1a; 前十…

Java,回形数

回形数基本思路&#xff1a; 用不同的四个分支分别表示向右向下向左向上&#xff0c;假如i表示数组的行数&#xff0c;j表示数组的列数&#xff0c;向右向左就是控制j的加减&#xff0c;向上向下就是控制i的加减。 class exercise {public static void main(String[] args){//回…

Jenkins 重新定义 pom 内容,打包

文章目录 源码管理构建 源码管理 添加仓库地址&#xff0c;拉取凭证&#xff0c;选择需要的分支 构建 勾选 构建环境 下删除原始 build 配置&#xff0c;防止文件错误 Pre Steps 构建前处理 pom.xml &#xff0c;例如我是需要删除该模块的所有子模块配置&#xff0c;我这里…