程序员技术开发

使用Path与Files操作文件

2020-08-13  本文已影响0人  岛上码农

Path

Path用于表示目录名,也可以是一个文件。路径以根目录开始的为据对路径,否则就是相对路径。例如假设使用Linux系统:

//绝对路径:/home/temp
Path absolute = Paths.get("/home", "temp");
Path absolute1 = Paths.get("/home/temp");
//相对路径:document/work/test.txt
Path relative = Paths.get("document", "work", "test.txt");
Path relative1 = Paths.get("document/work/test.txt");

Paths.get方法接收一个或多个字符串,并使用系统默认的路径分隔符(Linux为/,Windows为\)。Path类提供了一系列方法构建目录结构。

//path:/home
Path path = Paths.get("/home");
//other:/home/work
Path other = path.resolve("work");
//other1:/home/document
Path other1 = path.resolve("/home/document");
//other2:/home/work
Path other2 = path.resolve(Paths.get("work"));
//path:/home
Path path = Paths.get("/home/work");
//other:/home/document
Path other = path.resolveSibling("document");
//other1:/user/document
Path other1 = path.resolveSibling("/user/document");
//other2:/home/document/user
Path other2 = path.resolveSibling(Paths.get("document/user"));
//relative: ../document/user
Path relative = path.relativize(other2);
//absolute:/Volumns/ServerDevelop/home/work,其中/Volumns/ServerDevelop为工作目录
Path absolute = path.toAbsolutePath();

Files

Files类使得普通文件操作变得快捷。通过Path提供的文件路径,可以直接从文件读写行、字节、字符串内容,也可以使用流的方式处理文件读写。

public class FilesBasic {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("./DesignPattern/src/practise/lios/demo/alice.txt");
        //按行读取全部内容
        List<String> lines = Files.readAllLines(path);
        lines.stream().limit(10).forEach(System.out::println);

        //按字节读取全部内容
        byte[] bytes = Files.readAllBytes(path);
        String bytesToString = new String(bytes, 0 , 100);
        System.out.println("bytes:\n" + bytesToString);

        //通过InputStream读取内容
        InputStream inputStream = Files.newInputStream(path);
        Scanner inputScanner = new Scanner(inputStream, StandardCharsets.UTF_8);
        final int maxLine = 10;
        int line = 0;
        System.out.println("Input Stream:");
        while(inputScanner.hasNextLine() && line < maxLine) {
            String contents = inputScanner.nextLine();
            line ++;
            System.out.println(contents);
        }

        //通过OutputStream写内容到文件
        Path outputDirectory = Paths.get("output");
        //目录不存在的话创建目录
        if (! Files.exists(outputDirectory)) {
            Files.createDirectory(outputDirectory);
        }
        //将输出文件放入到新加的目录下
        Path outPath = outputDirectory.resolve("output.txt");
        boolean fileExists = Files.exists(outPath);
        OutputStream outputStream;
        if (fileExists) {
            outputStream = Files.newOutputStream(outPath, StandardOpenOption.APPEND);
        } else {
            outputStream = Files.newOutputStream(outPath, StandardOpenOption.CREATE);
        }
        outputStream.write(bytes, 0, 100);
        
        //文件移动、复制及删除
        Path parentPath = outputDirectory.toAbsolutePath().getParent();
        if (parentPath != null) {
            Path destinationFilePath = parentPath.resolve("output.txt");
            //如果文件存在则替换掉
            Path copyPath = Files.copy(outPath, destinationFilePath, StandardCopyOption.REPLACE_EXISTING);

            Path movedFilePath = parentPath.resolve("output1.txt");
            Path movedPath = Files.move(outPath, movedFilePath, StandardCopyOption.REPLACE_EXISTING);

            Files.delete(outputDirectory);
        }
    }
}

Files获取文件的基本信息

可以通过Files的方法获取文件的如下属性:

public static void showFileInfo(Path path) throws IOException {
    boolean fileExists = Files.exists(path);
    System.out.println("File exists: " + fileExists);
    if (fileExists) {
        boolean isHidden = Files.isHidden(path);
        System.out.println("File is hidden: " + isHidden);

        boolean isReadable = Files.isReadable(path);
        System.out.println("File is readable: " + isReadable);

        boolean isWritable = Files.isWritable(path);
        System.out.println("File is writable: " + isWritable);

        boolean isExecutable = Files.isExecutable(path);
        System.out.println("File is executable: " + isExecutable);

        boolean isDirectory = Files.isDirectory(path);
        System.out.println("File is directory: " + isDirectory);

        boolean isSymbolicLink = Files.isSymbolicLink(path);
        System.out.println("File is symbolic link: " + isSymbolicLink);

        boolean isRegularFile = Files.isRegularFile(path);
        if (isRegularFile) {
            long fileSize = Files.size(path);
            System.out.printf("File size: %.1fkB \n",(float)fileSize / 1024);
            //BasicFileAttributes包含上述的全部属性封装
            BasicFileAttributes attributes = Files.readAttributes(path, BasicFileAttributes.class);
            System.out.println("File size: " + attributes.size() + "bytes");
            System.out.println("File created at: " + attributes.creationTime());
            System.out.println("File last modified at: " + attributes.lastModifiedTime());
            System.out.println("File last accessed at: " + attributes.lastAccessTime());
        }
    }
}

目录遍历

Files.list(Path path)方法将遍历path下的目录(不包含下下级目录),返回Stream<Path>对象;Files.walk(Path path)返回path下的全部目录(包含全部子孙目录),返回Stream<Path>对象。

try (Stream<Path> entries = Files.list(path)) {
    entries.forEach(p -> {
        if (Files.isDirectory(p)) {
            System.out.println("Directory: " + p);
        } else {
            System.out.println("File: " + p);
        }
    });
}

try (Stream<Path> entries = Files.walk(path)) {
    entries.forEach(p -> {
        if (Files.isDirectory(p)) {
            System.out.println("Directory: " + p);
        } else {
            System.out.println("File: " + p);
        }
    });
}

文件访问效率

可以通过使用BufferedInputStream或FileChannel的map方法将文件映射到内存中,从而提高访问效率。其中FileChannel的map方法支持随机访问文件内容。

public class MemoryMapFile {
    public static long checkSumWithInputStream(Path filename) throws IOException {
        try (InputStream inputStream = Files.newInputStream(filename)) {
            CRC32 crc32 = new CRC32();

            int c;
            while((c = inputStream.read()) != -1) {
                crc32.update(c);
            }

            return crc32.getValue();
        }
    }

    public static long checkSumWithBufferedInputStream(Path filename) throws IOException {
        try (BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(filename))) {
            CRC32 crc32 = new CRC32();

            int c;
            while((c = inputStream.read()) != -1) {
                crc32.update(c);
            }

            return crc32.getValue();
        }
    }

    public static long checkSumWithRandomAccessFile(Path filename) throws IOException {
        try (RandomAccessFile file = new RandomAccessFile(filename.toFile(), "r")) {
            long length = file.length();

            CRC32 crc32 = new CRC32();
            for (long i = 0; i < length; ++i) {
                file.seek(i);
                int c = file.readByte();
                crc32.update(c);
            }

            return crc32.getValue();
        }
    }

    public static long checkSumWithMappedFile(Path filename) throws IOException {
        try (FileChannel fileChannel = FileChannel.open(filename)) {
            CRC32 crc32 = new CRC32();
            int length = (int)fileChannel.size();
            MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, length);

            for (int i = 0; i < length; ++i) {
                int c = buffer.get(i);
                crc32.update(c);
            }

            return crc32.getValue();
        }
    }

    public static void main(String[] args) throws IOException {
        Path path = Paths.get("./DesignPattern/src/practise/lios/demo/alice.txt");

        long start = System.currentTimeMillis();
        long crcValue = checkSumWithInputStream(path);
        long end = System.currentTimeMillis();
        System.out.println("CRC value: " + Long.toHexString(crcValue));
        System.out.println("InputStream Running time: " + (end - start) + " milliseconds");

        start = System.currentTimeMillis();
        crcValue = checkSumWithBufferedInputStream(path);
        end = System.currentTimeMillis();
        System.out.println("CRC value: " + Long.toHexString(crcValue));
        System.out.println("BufferedInputStream Running time: " + (end - start) + " milliseconds");

        start = System.currentTimeMillis();
        crcValue = checkSumWithRandomAccessFile(path);
        end = System.currentTimeMillis();
        System.out.println("CRC value: " + Long.toHexString(crcValue));
        System.out.println("RandomAccessFile Running time: " + (end - start) + " milliseconds");

        start = System.currentTimeMillis();
        crcValue = checkSumWithMappedFile(path);
        end = System.currentTimeMillis();
        System.out.println("CRC value: " + Long.toHexString(crcValue));
        System.out.println("MappedFile Running time: " + (end - start) + " milliseconds");
    }
}

运行结果如下:

CRC value: 11891d02
InputStream Running time: 185 milliseconds
CRC value: 11891d02
BufferedInputStream Running time: 9 milliseconds
CRC value: 11891d02
RandomAccessFile Running time: 221 milliseconds
CRC value: 11891d02
MappedFile Running time: 5 milliseconds

可以看到文件访问的效率为:MappedFile > BufferInputStream > InputStream > RandomAccessFile

上一篇下一篇

猜你喜欢

热点阅读