作者:ccccccc_fly_887 | 来源:互联网 | 2024-10-21 10:51
3、文件编程FileChannel获取FileChannle只能在阻塞模式下使用不能直接打开FileChannel,必须通过FileInputStream、FileOutput
3、文件编程
FileChannel
获取
FileChannle只能在阻塞模式下使用
不能直接打开FileChannel,必须通过FileInputStream、FileOutputStream或者RandomAccessFile来获取FileChannel,它们都有getChannel方法
通过FileInputStream获取的channel只能读
通过FileOutputStream获取的channel只能写
通过RandomAccessFile是否能读写根据构造的RandomAccessFile时的读写模式决定
读取
写入
写入的正确姿势如下
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)
大小
强制写入
- 操作系统处于性能的考虑,会将数据缓存,不是立刻写入磁盘,可以调用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:\0107TEST\\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:\0107TEST\\AkeyStart\\AkeyStart.bat\\..\\AkeyStart - 副本.bat");
System.out.println(path4);
System.out.println(path4.normalize());
E:0107TEST\AkeyStart\AkeyStart.bat\..\AkeyStart - 副本.bat
E:0107TEST\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() {
@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() {
@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() {
@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");
}