3、文件编程

FileChannel

获取

  • FileChannle只能在阻塞模式下使用
  • 不能直接打开FileChannel,必须通过FileInputStream、FileOutputStream或者RandomAccessFile来获取FileChannel,它们都有getChannel方法
  • 通过FileInputStream获取的channel只能读
  • 通过FileOutputStream获取的channel只能写
  • 通过RandomAccessFile是否能读写根据构造的RandomAccessFile时的读写模式决定

读取

  • 会从channel读取数据跳虫ByteBuffer,返回值表示读到了多少个字节,-1表示到达了文件的末尾
int readBytes = channel.read(buffer);

写入

  • 写入的正确姿势如下
ByteBuffer buffer = ...;
buffer.put(...); // 存入数据
buffer,flip(); // 切换读模式
while(buffer.hasRemaining()) {
    channel.write(buffer);
}

在while中调用channel.write方法并不一定保证一次将buffer中的全部内容写入channel

关闭

  • channel必须关闭,不过调用了FileInoutStream、FileOutputStream或者RandomAccessFile的close方法会间接调用channel的close方法

位置

  • 获取当前位置
long pos = channel.position();
  • 设置当前位置
long newPos = ....;
channel.position(newPos);
  • 设置当前位置时,如果设置为未见末尾
    这时读取会返回-1
    这时写入,会追加内容,但要注意如果position超过了文件末尾,再写入新内容和原来末尾之间会有空洞(00)

大小

  • 使用size方法获取文件大小

强制写入

  • 操作系统处于性能的考虑,会将数据缓存,不是立刻写入磁盘,可以调用force(true)方法将文件内容和元数据(文件的权限等信息立刻写入磁盘)

两个channel传输数据

public static void main(String[] args) {
        String source = "word1.txt";
        String target = "word3.txt";
        try (
                FileChannel from = new FileInputStream(source).getChannel();
                FileChannel to = new FileOutputStream(target).getChannel();
        ) {
            // 代码简洁,效率高,底层一版会调用操作系统的零拷贝优化shangxin
            // 传输数据有上限,最多2G
            from.transferTo(0, from.size(), to);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

优化(可传输大于2G的文件):

public static void main(String[] args) {
        String source = "word1.txt";
        String target = "word4.txt";
        try (
                FileChannel from = new FileInputStream(source).getChannel();
                FileChannel to = new FileOutputStream(target).getChannel();
        ) {

            long size = from.size();
            // left  表示还有多少字节
            for (long left = size; left > 0; ) {
                System.out.println("position:"+(size-left)+",left:"+left);
                left -= from.transferTo((size - left), left, to);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

Path

  • JDK 引入Path和Paths类
  • Path用来表示文件路径
  • Paths时工具类,用来获取Path
// 相对路径 使用usr.dir 环境变量来定位 word1.txt
Path path = Paths.get("word1.txt");
// 绝对路径
Path path2 = Paths.get("E:\\210107TEST\\AkeyStart\\AkeyStart.bat");
// 绝对路径
Path path1 = Paths.get("E:/210107TEST/AkeyStart/AkeyStart.bat");
// 代表 E:/210107TEST/AkeyStart/AkeyStart.bat
Path path3 = Paths.get("E:/210107TEST/AkeyStart", "AkeyStart.bat");
  • **. **代表当前路径
  • ..代表了上一级路径

java如何用netty如何解析读取modbus报文_ide

```java
  Path path4 = Paths.get("E:\\210107TEST\\AkeyStart\\AkeyStart.bat\\..\\AkeyStart - 副本.bat");
  System.out.println(path4);
  System.out.println(path4.normalize());

  E:\210107TEST\AkeyStart\AkeyStart.bat\..\AkeyStart - 副本.bat
  E:\210107TEST\AkeyStart\AkeyStart - 副本.bat
```

File

  • 检查文件是否存在
Path path = Paths.get("word10.txt");
System.out.println(Files.exists(path)); // true false
  • 创建一级目录
Path path1 = Paths.get("E:\\kms\\dgj");
  Files.createDirectory(path1);
  • 创建多级目录
Path path1 = Paths.get("E:\\kms\\test\\dgj");
 Files.createDirectories(path1);
  • 拷贝文件
// word10.txt没有
Path path1 = Paths.get("word1.txt");
 Path path2 = Paths.get("word10.txt");
 Files.copy(path1,path2);

// word2.txt有,覆盖
 Path path1 = Paths.get("word1.txt");
 Path path2 = Paths.get("word2.txt");
Files.copy(path1,path2, StandardCopyOption.REPLACE_EXISTING);

如果文件存在,抛 java.nio.file.FileAlreadyExistsException

  • 移动文件
Path path1 = Paths.get("word1.txt");
  Path path2 = Paths.get("word2.txt");
  // StandardCopyOption.ATOMIC_MOVE 保证文件移动的原子性
  Files.move(path1,path2,StandardCopyOption.ATOMIC_MOVE);
  • 删除文件
Path path1 = Paths.get("word2.txt");
Files.delete(path1);

文件不存在:java.nio.file.NoSuchFileException: word21.txt

  • 删除目录
Path path1 = Paths.get("E:\\kms\\dgj");
Files.delete(path1);
  • 遍历文件夹(访问者模式)
public static void dirAndFile() {
        try {
            // 文件夹数
            AtomicInteger dircount = new AtomicInteger();
            // 文件数
            AtomicInteger filecount = new AtomicInteger();
            Files.walkFileTree(Paths.get("D:\\mavenjar"), new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)  throws IOException {
                    dircount.incrementAndGet();
                    System.out.println("dir--->:"+dir);
                    return FileVisitResult.CONTINUE;
                }
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                        throws IOException
                {
                    filecount.incrementAndGet();
                    System.out.println("file--->:"+file);
                    return FileVisitResult.CONTINUE;
                }
            });
            System.out.println("dircount:"+dircount+"个文件");
            System.out.println("dircount:"+filecount+"个文件夹");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

遍历文件夹中有多少个jar

public static void selectJar() {
        try {
            AtomicInteger atomicInteger = new AtomicInteger();
            Files.walkFileTree(Paths.get("D:\\mavenjar"), new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                        throws IOException {
                if(file.toString().endsWith(".jar")){
                    atomicInteger.incrementAndGet();
                    System.out.println(file);
                }
                    return super.visitFile(file,attrs);
                }
            });
            System.out.println(atomicInteger);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 删除多级目录
Files.delete(Paths.get("D:\\ruoyi")); //java.nio.file.DirectoryNotEmptyException: D:\ruoyi 有文件 删除失败
public static void deleteDir() {
        // 删除多级目录
        try {
            Files.walkFileTree(Paths.get("D:\\ruoyi"), new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                        throws IOException {
                    Files.delete(file);
                    return super.visitFile(file, attrs);
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc)
                        throws IOException {
                    Files.delete(dir);
                    return FileVisitResult.CONTINUE;
                }

            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 文件夹拷贝
public static void backups() throws IOException {
        String source = "D:\\代码备份";
        String target = "D:\\代码备份testnio";

        Files.walk(Paths.get(source)).forEach(path -> {

            // 是否是目录
            try {
                String replace = path.toString().replace(source, target);
                if (Files.isDirectory(path)) {
                    Files.createDirectory(Paths.get(replace));
                }
                // 是否是文件
                else if (Files.isRegularFile(path)) {
                    Files.copy(path, Paths.get(replace));
                }
            } catch (IOException E) {

            }
        });
        System.out.println("copy complete");
    }