NIO操作文件读写

第一章

第一节,Buffuer

案例一  从buffur 读出数据,

创建了一个 FileInputStream 对象,并通过调用 getChannel() 方法获取了与之关联的 FileChannel。然后,

我们创建了一个 ByteBuffer,并使用 channel.read(buffer) 方法从文件中读取数据到缓冲区。最后,我们通过循环将缓冲区中的数据打印出来。

package cn.itcast.netty.c1;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class TestByteBuffer {
    public static void main(String[] args) {
        // 使用 FileChannel 从文件中读取数据到 ByteBuffer
        try (FileChannel channel = new FileInputStream("data.txt").getChannel()) { // 准备缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(10);
            // 从 channel 读取数据,向 buffer 写入
            channel.read(buffer);
            // 打印 buffer 的内容
            buffer.flip(); // 切换到读模式
            while (buffer.hasRemaining()) {
                System.out.print((char) buffer.get());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
读Buffuer 读数据

读数据可以通过判断一下还有没有数据

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class TestByteBuffer {
    public static void main(String[] args) {
        // 使用 FileChannel 从文件中读取数据到 ByteBuffer
        try (FileChannel channel = new FileInputStream("data.txt").getChannel()) { // 准备缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(10);
            while (true) {
                // 从 channel 读取数据,向 buffer 写入
                int len = channel.read(buffer);
                if (len == -1) { // 没有内容了
                    break;
                }
                // 打印 buffer 的内容
                buffer.flip(); // 切换至读模式
                while (buffer.hasRemaining()) { // 是否还有剩余未读数据
                    byte b = buffer.get();
                    System.out.println((char) b);
                }
                buffer.clear(); // 清空缓冲区以准备下一次读取
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

读写操作

import static cn.itcast.netty.c1.ByteBufferUtil.debugAll;

public class TestByteBufferReadWrite {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(10); // 创建一个容量为10的ByteBuffer
        buffer.put((byte) 0x61); // 向buffer中放入字符'a' (ASCII码为0x61)
        debugAll(buffer); // 打印buffer的详细信息
        buffer.put(new byte[]{0x62, 0x63, 0x64}); // 向buffer中放入字节数组,包含字符'b', 'c', 'd'
        debugAll(buffer); // 打印buffer的详细信息

        System.out.println(buffer.get()); // 从buffer中读取一个字节并打印,这里会打印出'a'
        buffer.flip(); // 将buffer的模式从写模式切换到读模式
        System.out.println(buffer.get()); // 再次从buffer中读取一个字节并打印,这里会打印出'b'
        debugAll(buffer); // 打印buffer的详细信息
        buffer.compact(); // 清除buffer中的未读数据,已读数据之前的区域会被清空
        debugAll(buffer); // 打印buffer的详细信息
        buffer.put(new byte[]{0x65, 0x6F}); // 向buffer中放入字节数组,包含字符'e', 'o'
        debugAll(buffer); // 打印buffer的详细信息
    }
}

代码示例三 ,我们创建了一个 ByteBuffer,并使用 while 循环不断从文件中读取数据到缓冲区。当 channel.read(buffer) 返回 -1 时,表示文件已经读取完毕

,我们跳出循环。接下来,我们通过循环将缓冲区中的数据逐个打印出来。在每次循环结束时,我们使用 buffer.clear() 方法清空缓冲区,

以便下次读取。如果在读取过程中发生任何 IOException,我们会捕获异常并打印堆栈跟踪。

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class TestByteBuffer {
    public static void main(String[] args) {
        // 使用 FileChannel 从文件中读取数据到 ByteBuffer
        try (FileChannel channel = new FileInputStream("data.txt").getChannel()) { // 准备缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(10);
            while (true) {
                // 从 channel 读取数据,向 buffer 写入
                int len = channel.read(buffer);
                if (len == -1) { // 没有内容了
                    break;
                }
                // 打印 buffer 的内容
                buffer.flip(); // 切换至读模式
                while (buffer.hasRemaining()) { // 是否还有剩余未读数据
                    byte b = buffer.get();
                    System.out.println((char) b);
                }
                buffer.clear(); // 清空缓冲区以准备下一次读取
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

标记上一次打印位置

public static void main(String[] args) {
    // 假设buffer已经被填充了数据,并且已经flip切换到读模式
    System.out.println((char) buffer.get()); // 打印buffer中的第一个字符
    System.out.println((char) buffer.get()); // 打印buffer中的第二个字符
    
    buffer.mark(); // 在当前位置做一个标记
    
    System.out.println((char) buffer.get()); // 打印buffer中的第三个字符
    System.out.println((char) buffer.get()); // 打印buffer中的第四个字符
    
    buffer.reset(); // 将position重置到之前标记的位置
    
    System.out.println((char) buffer.get()); // 重新打印buffer中的第三个字符
    System.out.println((char) buffer.get()); // 重新打印buffer中的第四个字符
    
    // get(i)不会改变读索引的位置
    System.out.println((char) buffer.get(3)); // 直接获取索引为3位置的字符,不改变position
    
    debugAll(buffer); // 打印buffer的详细信息
}

分读同写

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.io.RandomAccessFile;
import java.io.IOException;

public class ReadFileWithRandomAccess {
    public static void main(String[] args) {
        try (RandomAccessFile file = new RandomAccessFile("helloworld/3parts.txt", "rw")) {
            FileChannel channel = file.getChannel();
            
            // 分配三个ByteBuffer,用于存储从文件中读取的数据
            ByteBuffer a = ByteBuffer.allocate(3);
            ByteBuffer b = ByteBuffer.allocate(3);
            ByteBuffer c = ByteBuffer.allocate(5);
            
            // 从文件中读取数据到这三个ByteBuffer中
            channel.read(new ByteBuffer[]{a, b, c});
            
            // 确保每个ByteBuffer都处于读模式
            a.flip();
            b.flip();
            c.flip();
            
            // 打印每个ByteBuffer的内容
            debug(a);
            debug(b);
            debug(c);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    // 假设debug方法是用来打印ByteBuffer的内容
    private static void debug(ByteBuffer buffer) {
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        System.out.println();
    }
}

上一次没处理到下一次处理的示例‘

public class ByteBufferSplit {
    public static void main(String[] args) {
        ByteBuffer source = ByteBuffer.allocate(32);
        source.put("Hello, world\n" +
                   "I'm zhangsan\n" +
                   "How are you?\n".getBytes());
        split(source);
        source.put("What's your name?\n".getBytes());
        split(source);
    }

    private static void split(ByteBuffer source) {
        source.flip();
        while (source.hasRemaining()) {
            // 找到一条完整消息的结束符'\n'
            if (source.get(source.position()) == '\n') {
                int length = source.position() + 1 - source.position(); // 计算当前消息的长度
                
                // 把这条完整消息存入新的ByteBuffer
                ByteBuffer target = ByteBuffer.allocate(length);
                // 从source读取,向target写入
                for (int j = 0; j< length; j++) {
                    target.put(source.get());
                }
                target.flip(); // 确保target处于读模式
                // 这里可以处理或打印target的内容
                System.out.println(new String(target.array(), 0, target.limit()));
                source.position(source.position() + 1); // 移动source的位置到下一条消息的开始
            } else {
                source.position(source.position() + 1); // 如果不是结束符,移动到下一个位置继续查找
            }
        }
    }
}

第二章,文件读写

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteBufferWriteExample {
    public static void main(String[] args) {
        // 创建一个ByteBuffer并分配空间
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        
        // 向ByteBuffer中存入数据
        buffer.put("This is some example text.\n".getBytes());
        
        // 切换ByteBuffer到读模式,准备写入操作
        buffer.flip();
        
        // 获取FileChannel,准备写入文件
        try (FileOutputStream fos = new FileOutputStream("output.txt");
             FileChannel channel = fos.getChannel()) {
            
            // 当ByteBuffer中还有数据时,循环写入FileChannel
            while (buffer.hasRemaining()) {
                channel.write(buffer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

复制文件

import java.nio.channels.FileChannel;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileTransferExample {
    public static void main(String[] args) {
        // 定义源文件的路径
        String from = "helloworld/data.txt";
        // 定义目标文件的路径
        String to = "helloworld/to.txt";
        // 记录文件传输操作开始的时间
        long start = System.nanoTime();
        
        try (
            // 创建读取源文件的FileChannel
            FileChannel fromChannel = new FileInputStream(from).getChannel();
            // 创建写入目标文件的FileChannel
            FileChannel toChannel = new FileOutputStream(to).getChannel();
        ) {
            // 使用transferTo方法将数据从源FileChannel传输到目标FileChannel
            fromChannel.transferTo(0, fromChannel.size(), toChannel);
        } catch (IOException e) {
            // 捕获并处理可能发生的IOException
            e.printStackTrace();
        } finally {
            // 记录文件传输操作结束的时间
            long end = System.nanoTime();
            // 计算并打印文件传输操作所用的时间,单位为毫秒
            System.out.println("transferTo 用时: " + (end - start) / 1_000_000.0 + " ms");
        }
    }
}

大文件读写

import java.nio.channels.FileChannel;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class TestFileChannelTransferTo {
    public static void main(String[] args) {
        try (
            // 创建读取源文件的FileChannel
            FileChannel from = new FileInputStream("data.txt").getChannel();
            // 创建写入目标文件的FileChannel
            FileChannel to = new FileOutputStream("to.txt").getChannel();
        ) {
            // 获取源文件的大小
            long size = from.size();
            // left变量代表还剩余多少字节未传输
            for (long left = size; left > 0; ) {
                // 使用transferTo方法传输剩余的字节,可能不会传输全部剩余字节,取决于操作系统的限制
                left -= from.transferTo((size - left), Math.min(left, Integer.MAX_VALUE), to);
            }
        } catch (IOException e) {
            // 捕获并处理可能发生的IOException
            e.printStackTrace();
        }
    }
}

统计文件个数

import java.io.IOException;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;

public class TestFilesWalkFileTree {
    public static void main(String[] args) throws IOException {
        AtomicInteger dirCount = new AtomicInteger();
        AtomicInteger fileCount = new AtomicInteger();
        
        // 遍历指定路径下的所有文件和目录
        Files.walkFileTree(Paths.get("C:\\Program Files\\Java\\jdk1.8.0_91"), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println("====> " + dir);
                dirCount.incrementAndGet(); // 增加目录计数
                return super.preVisitDirectory(dir, attrs);
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println(file);
                fileCount.incrementAndGet(); // 增加文件计数
                return super.visitFile(file, attrs);
            }
        });
        
        // 打印目录和文件的总数
        System.out.println("dir count: " + dirCount);
        System.out.println("file count: " + fileCount);
    }
}

统计文件和文件夹个数,的示例二

import java.io.IOException;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;

public class TestFilesWalkFileTree {
    public static void main(String[] args) throws IOException {
        AtomicInteger dirCount = new AtomicInteger();
        AtomicInteger fileCount = new AtomicInteger();
        
        // 遍历指定路径下的所有文件和目录
        Files.walkFileTree(Paths.get("C:\\Program Files\\Java\\jdk1.8.0_91"), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println("====> " + dir);
                dirCount.incrementAndGet(); // 增加目录计数
                return super.preVisitDirectory(dir, attrs);
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println(file);
                fileCount.incrementAndGet(); // 增加文件计数
                return super.visitFile(file, attrs);
            }
        });
        
        // 打印目录和文件的总数
        System.out.println("dir count: " + dirCount);
        System.out.println("file count: " + fileCount);
    }
}
统计文件个数

遍历子文件件和子文件夹

import java.io.IOException;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;

public class TestFilesWalkFileTree {
    public static void main(String[] args) throws IOException {
        // 创建两个AtomicInteger对象来跟踪目录和文件的数量
        AtomicInteger dirCount = new AtomicInteger();
        AtomicInteger fileCount = new AtomicInteger();
        
        // 使用Files.walkFileTree方法遍历指定路径下的所有文件和目录
        Files.walkFileTree(
            Paths.get("C:\\Program Files\\Java\\jdk1.8.0_91"), // 指定要遍历的路径
            new SimpleFileVisitor<Path>() { // 提供一个自定义的SimpleFileVisitor来处理遍历过程中的每个文件和目录
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    System.out.println("====> " + dir); // 打印当前遍历到的目录
                    dirCount.incrementAndGet(); // 增加目录计数
                    return super.preVisitDirectory(dir, attrs); // 继续遍历
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    System.out.println(file); // 打印当前遍历到的文件
                    fileCount.incrementAndGet(); // 增加文件计数
                    return super.visitFile(file, attrs); // 继续遍历
                }
            }
        );
        
        // 打印目录和文件的总数
        System.out.println("dir count: " + dirCount);
        System.out.println("file count: " + fileCount);
    }
}

查找文件夹下面的jar 文件

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;

public class TestFilesWalkFileTree {
    public static void main(String[] args) throws IOException {
        AtomicInteger jarCount = new AtomicInteger();
        Files.walkFileTree(Paths.get("C:\\Program Files\\Java\\jdk1.8.0_91"), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                if (file.toString().endsWith(".jar")) {
                    System.out.println(file);
                    jarCount.incrementAndGet();
                }
                return super.visitFile(file, attrs);
            }
        });
        System.out.println("Jar count: " + jarCount);
    }
}

删除文件

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

public class TestFilesWalkFileTree {
    public static void main(String[] args) throws IOException {
        // 删除指定文件
        try {
            Files.delete(Paths.get("D:\\Snipaste-1.16.2-x64-副本"));
        } catch (NoSuchFileException e) {
            System.err.println("文件不存在: " + e.getFile());
        }

        // 遍历指定路径下的所有文件,并删除它们
        Files.walkFileTree(Paths.get("O:\\snipaste-1.16.2-x64-副本"), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println(file); // 打印文件路径
                Files.delete(file); // 删除文件
                return super.visitFile(file, attrs);
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                System.out.println("<==== 退出 " + dir); // 打印目录路径
                Files.delete(dir); // 删除目录
                return super.postVisitDirectory(dir, exc);
            }
        });
    }
}

复制文件夹,下所有文件,和文件夹

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

public class TestFilesCopy {
    public static void main(String[] args) {
        String source = "C:\\Snipaste-1.16.2-x64";
        String target = "C:\\Snipaste-1.16.2-x64aaa";

        Files.walk(Paths.get(source)).forEach(path -> {
            try {
                String targetName = path.toString().replace(source, target);

                // 如果是目录
                if (Files.isDirectory(path)) {
                    Files.createDirectory(Paths.get(targetName));
                }
                // 如果是普通文件
                else if (Files.isRegularFile(path)) {
                    Files.copy(path, Paths.get(targetName));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }
}

 

posted @ 2024-06-17 18:50  谢双元小号  阅读(210)  评论(0)    收藏  举报