Netty基础02-NIO-文件编程
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
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"); }
-