微商城网站建设怎么样,发稿是什么意思,进什么公司,做网站的类型3. 文件编程
3.1 FileChannel
⚠️ FileChannel 工作模式 FileChannel 只能工作在阻塞模式下 获取
不能直接打开 FileChannel#xff0c;必须通过 FileInputStream、FileOutputStream 或者 RandomAccessFile 来获取 FileChannel#xff0c;它们都有 getChannel 方法
通过…3. 文件编程
3.1 FileChannel
⚠️ FileChannel 工作模式 FileChannel 只能工作在阻塞模式下 获取
不能直接打开 FileChannel必须通过 FileInputStream、FileOutputStream 或者 RandomAccessFile 来获取 FileChannel它们都有 getChannel 方法
通过 FileInputStream 获取的 channel 只能读通过 FileOutputStream 获取的 channel 只能写通过 RandomAccessFile 是否能读写根据构造 RandomAccessFile 时的读写模式决定
读取
会从 channel 读取数据填充 ByteBuffer返回值表示读到了多少字节-1 表示到达了文件的末尾
int readBytes channel.read(buffer);写入
写入的正确姿势如下 SocketChannel
ByteBuffer buffer ...;
buffer.put(...); // 存入数据
buffer.flip(); // 切换读模式while(buffer.hasRemaining()) {channel.write(buffer);
}在 while 中调用 channel.write 是因为 write 方法并不能保证一次将 buffer 中的内容全部写入 channel
关闭
channel 必须关闭不过调用了 FileInputStream、FileOutputStream 或者 RandomAccessFile 的 close 方法会间接地调用 channel 的 close 方法
位置
获取当前位置
long pos channel.position();设置当前位置
long newPos ...;
channel.position(newPos);设置当前位置时如果设置为文件的末尾
这时读取会返回 -1这时写入会追加内容但要注意如果 position 超过了文件末尾再写入时在新内容和原末尾之间会有空洞00
大小
使用 size 方法获取文件的大小
强制写入
操作系统出于性能的考虑会将数据缓存不是立刻写入磁盘。可以调用 force(true) 方法将文件内容和元数据文件的权限等信息立刻写入磁盘
3.2 两个 Channel 传输数据
String FROM helloword/data.txt;
String TO helloword/to.txt;
long start System.nanoTime();
try (FileChannel from new FileInputStream(FROM).getChannel();FileChannel to new FileOutputStream(TO).getChannel();) {from.transferTo(0, from.size(), to);
} catch (IOException e) {e.printStackTrace();
}
long end System.nanoTime();
System.out.println(transferTo 用时 (end - start) / 1000_000.0);输出
transferTo 用时8.2011超过 2g 大小的文件传输
public class TestFileChannelTransferTo {public static void main(String[] args) {try (FileChannel from new FileInputStream(data.txt).getChannel();FileChannel to new FileOutputStream(to.txt).getChannel();) {// 效率高底层会利用操作系统的零拷贝进行优化, 2g 数据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();}}
}实际传输一个超大文件
position:0 left:7769948160
position:2147483647 left:5622464513
position:4294967294 left:3474980866
position:6442450941 left:13274972193.3 Path
jdk7 引入了 Path 和 Paths 类
Path 用来表示文件路径Paths 是工具类用来获取 Path 实例
Path source Paths.get(1.txt); // 相对路径 使用 user.dir 环境变量来定位 1.txtPath source Paths.get(d:\\1.txt); // 绝对路径 代表了 d:\1.txtPath source Paths.get(d:/1.txt); // 绝对路径 同样代表了 d:\1.txtPath projects Paths.get(d:\\data, projects); // 代表了 d:\data\projects. 代表了当前路径.. 代表了上一级路径
例如目录结构如下
d:|- data|- projects|- a|- b代码
Path path Paths.get(d:\\data\\projects\\a\\..\\b);
System.out.println(path);
System.out.println(path.normalize()); // 正常化路径会输出
d:\data\projects\a\..\b
d:\data\projects\b3.4 Files
检查文件是否存在
Path path Paths.get(helloword/data.txt);
System.out.println(Files.exists(path));创建一级目录
Path path Paths.get(helloword/d1);
Files.createDirectory(path);如果目录已存在会抛异常 FileAlreadyExistsException不能一次创建多级目录否则会抛异常 NoSuchFileException
创建多级目录用
Path path Paths.get(helloword/d1/d2);
Files.createDirectories(path);拷贝文件
Path source Paths.get(helloword/data.txt);
Path target Paths.get(helloword/target.txt);Files.copy(source, target);如果文件已存在会抛异常 FileAlreadyExistsException
如果希望用 source 覆盖掉 target需要用 StandardCopyOption 来控制
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);移动文件
Path source Paths.get(helloword/data.txt);
Path target Paths.get(helloword/data.txt);Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);StandardCopyOption.ATOMIC_MOVE 保证文件移动的原子性
删除文件
Path target Paths.get(helloword/target.txt);Files.delete(target);如果文件不存在会抛异常 NoSuchFileException
删除目录
Path target Paths.get(helloword/d1);Files.delete(target);如果目录还有内容会抛异常 DirectoryNotEmptyException
遍历目录文件
public static void main(String[] args) throws IOException {Path path Paths.get(C:\\Program Files\\Java\\jdk1.8.0_91);AtomicInteger dirCount new AtomicInteger();//文件夹原子计数器线程安全AtomicInteger fileCount new AtomicInteger();//文件原子计数器线程安全Files.walkFileTree(path, new SimpleFileVisitorPath(){Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {System.out.println(dir);dirCount.incrementAndGet();//遍历到文件夹时增加计数return super.preVisitDirectory(dir, attrs);}Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {System.out.println(file);fileCount.incrementAndGet();//遍历到文件时增加计数return super.visitFile(file, attrs);}});System.out.println(dirCount); // 133System.out.println(fileCount); // 1479
}统计 jar 的数目
Path path Paths.get(C:\\Program Files\\Java\\jdk1.8.0_91);
AtomicInteger fileCount new AtomicInteger();
Files.walkFileTree(path, new SimpleFileVisitorPath(){Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {if (file.toFile().getName().endsWith(.jar)) {//file.toString().endsWith(.jar)fileCount.incrementAndGet();}return super.visitFile(file, attrs);}
});
System.out.println(fileCount); // 724删除多级目录
Path path Paths.get(d:\\a);
Files.walkFileTree(path, new SimpleFileVisitorPath(){Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.delete(file);return super.visitFile(file, attrs);}Overridepublic FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {Files.delete(dir);return super.postVisitDirectory(dir, exc);}
});⚠️ 删除很危险 删除是危险操作确保要递归删除的文件夹没有重要内容 拷贝多级目录
long start System.currentTimeMillis();
String source D:\\Snipaste-1.16.2-x64;
String target D:\\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();}
});
long end System.currentTimeMillis();
System.out.println(end - start);