1. File 类的作用?
- File类是java.io包下代表与平台无关的文件和目录,通过File可以操作文件和目录(增, 删, 改)
2. 创建File对象,以及调用File对象的方法操作文件或目录?
- 创建File对象
File file = new File("绝对/相对路径"); - 调用 File 对象的方法
- 操作文件的方法: getName(), getPath(), getAbsolutePath(), getParent(), renameTo(File filename), exists(), canWrite(), canRead(),
isFile(), isDirectory(), isAbsolute(), length(), createNewFile(), delete(), createTempFile(String prefix, String suffix),
createTempFile(String prefix, String suffix, File Directory), deleteOnExit() - 操作目录: mkdir(), String[] list(), File[] listFiles(), static File[] listRoots()
- 操作文件的方法: getName(), getPath(), getAbsolutePath(), getParent(), renameTo(File filename), exists(), canWrite(), canRead(),
3. 文件过滤器(File的list()方法)例子?
// 查找 filePath 路径下的以 ".java" 结尾的文件
import java.io.File;
public class FilenameFilterTest {
public static void fileNameFilter(String filePath, String patten){
File file = new File(filePath);
String[] nameList = file.list((dir, name) -> name.endsWith(patten)
|| new File(name).isDirectory());
for (String name : nameList){
System.out.println(name);
}
}
public static void main(String[] args){
String filePath = "D:\\File\\Java\\JavaBase\\src\\xyz\\xmcs\\CrazyJava\\IO";
String patten = ".java";
fileNameFilter(filePath, patten);
}
4. 什么是流? 什么是输入? 输出?
- 流: 在Java中把不同的输入/输出源抽象为 "流"(Stream), 通过流的方式允许Java程序使用相同的方式来访问不同的输入/输出源
- 输入: 指的是从程序外部读取数据
- 输出: 指的是向程序外部输出数据
- 输入/输出的主题是程序, 对程序来说, 将数据从外部读取到程序, 就是输入, 而将数据从程序输出到外部就是输出
5. 流的分类?
- 按照流的流向为:
- 输入流: 只能从中读取数据, 不能写入数据, 基类为: InputStream 和 Reader
- 输出流: 只能向其写入数据, 不能读取数据, 基类为: OutputStream 和 Writer
- 按照处理的大小分为:
- 字节流: 处理的8为字节; 字节流字符流的用法一模一样; 基类: InputStream 和 OutputStream
- 字符流: 处理的16为字符 基类: Reader 和 Writer
- 按照流的角色分为:
- 节点流: 可以从/向特定的IO设备读/写数据的流, 程序直接连接到实际的物流节点
- 处理流: 包装一个已存在的流, 对其进行封装或连接; 通过使用处理流来包装不同的节点流, 既可以消除不同的节点流的实现差异, 也可以提供更方便的方法来完成输入/输出功能
6. InputStream/Reader 基类,其常用方法, 及例子?
InputStream/Reader 是所有输入流的抽象基类, 本身不能创建实例来执行输入; 但分别有一个用于读取文件的输入流:FileInputStream 和 FileReader, 都是节点流--会直接和指定的文件关联
-
InputStream/Reader 的常用方法类似(区别只是一个处理字节, 一个处理字符):
- int read(): 从输入流中读取单个字节/字符, 返回所读取的字节/字符数据
- int read(byte[]/char[] b): 从输入流中最多读取 b.length个字节/字符的数据, 并将其存储在字节/字符数据b中, 返回实际读取的字节/字符数
- int read(byte[]/char[] b, int off, int len): 从输入流中最多读取 len 长度的字节/字符数据, 并将其存储在字节/字符数据b中, 放入数据b中时, 并不是从数据的起点来时, 而是从off的位置开始, 返回实际读取的字节/字符数
-
InputStream/ Reader 移动指针的方法:
- void mark(int readAheadLimit): 在记录指针当前位置设置一个标记(mark)
- boolean markSupported(): 判断此输入流是否支持mark() 操作
- void reset(): 将此流的记录指针重新定位到上一次记录标记(mark)的位置
- long skip(long n): 记录指针向前移动n个字节/字符
例子:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileInputStreamTest {
// InputStream 用法
public static void inputStream(String path) {
try(FileInputStream fis = new FileInputStream(path)){
// 创建一个长度为512的字节数组("竹筒")
byte[] b = new byte[512];
// 用于保存实际读取的字节数
int hasRead = 0;
// 使用循环来重复"取水"过程
while ((hasRead = fis.read(b)) != -1) {
System.out.println(new String(b, 0, hasRead));
}
}catch(Exception e){
e.printStackTrace();}
}
// FileReader 用法
public static void readerTest(String path) {
try(FileReader fr = new FileReader(path)){
char[] c = new char[512];
int hasRead = 0;
while((hasRead = fr.read(c)) != -1){
System.out.println(new String(c, 0, hasRead));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String path = "D:\\File\\Java\\ShoppingMall\\mall\\src\\jeffmall\\Mall.java";
long start = System.currentTimeMillis();
// inputStream(path);
readerTest(path);
System.out.println(System.currentTimeMillis() - start);
}
}
7. OutputStream/Writer 基类,其常用方法, 及例子?
- OutputStream/Writer 是所有输出类的基类, 本身不能创建实例, 但是可以通过 FileOutputStream/FileWriter 来创建实例
- OutputStream/Writer 常用方法:
- void write(int c): 将指定字节/字符输出到输出流中, c既可以是字节, 也可以是字符
- void write(byte[]/char[] buf): 将字节/字符数组中的数据输出到指定的输出流中
- void write(byte[]/char[] buf, int off, int len): 将字节/字符数组中从off位置开始, 长度为len的字符输出到指定输出流中
- Writer 特有的方法:
- void write(String str): 将字符串str里包含的字符输出到指定输出流中
- void write(String str, int off, int len): 将 str 字符串里从 off 位置开始, 长度为 len 的字符输出到指定输出流中
- 例子:
import java.io.*;
public class FileOutputStreamTest {
// FileOutputStream 实例
public static void fileOutPutStream(String sourcePath, String newPath) {
try (
FileInputStream fis = new FileInputStream(sourcePath);
FileOutputStream fos = new FileOutputStream(newPath)) {
byte[] bbuf = new byte[512];
int hasRead = 0;
while ((hasRead = fis.read(bbuf)) != -1){
fos.write(bbuf, 0, hasRead);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// FileWriter 实例
public static void writer(String sourcePath, String newPath) {
try (
FileReader fr = new FileReader(sourcePath);
FileWriter fw = new FileWriter(newPath)){
char[] bbuf = new char[256];
int hasRead = 0;
while((hasRead = fr.read(bbuf)) != -1){
fw.write(bbuf, 0, hasRead);
}
}catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
String sourcePath = "C:\\Users\\Desktop\\Login.html";
String newPath = "C:\\Users\\Desktop\\login02.txt";
fileOutPutStream(sourcePath, newPath);
// writer(sourcePath, newPath);
System.out.println(System.currentTimeMillis() - start);
}
}
8. 处理流(或叫装饰流,外层流)?
- 使用处理流的优势就是可以隐藏底层设备节点流的差异, 并对外提供更加方便的输入/输出方法
- 使用处理流来包装节点流, 程序通过处理流来执行输入/输出功能, 让节点流与底层的I/O设备,文件交互
- 处理流也就是装饰流, 它需要直接以物理IO节点作为构造器的参数
9. 常用的处理流?
-
常用的底层输入流:
- ByteArrayInputStream - 输入字节数组
- StringBufferInputStream - 输入字符串
- FileInputStream - 从文件输入,即打开一个文件
- PipedInputStream - 管道输入流,构造器接受一个管道输出流
- FileReader - 读取文件
- StringReader - 读取字符串
- CharArrayReader - 读取字符数组
- PipedReader - 读取管道数据
-
常用的输入处理流:
- DataInputStream: 从流中读取基本类型数据
- BufferedInputStream: 采用缓冲区方式读写
- LineNumberInputStream: 来跟踪输入流中的行号
- BufferedReader - 通用的带缓冲读取字符
- LineNumberReader - 带有行号API的读取
-
常用的底层输出流:
- ByteArrayOutputStream: 字节数组输出,实际上是在内存中创建一个缓冲区输出
- FileOutputStream: 输出到文件
- PipedOutputStream: 管道输出流,构造器接受一个管道输入流
- FileWriter - 写文件
- StringWriter - 写字符串
- CharArrayWriter - 写字符数组
- PipedWriter - 向管道中写入字符
-
常用的输出处理流:
- DataOutputStream - 向流中写入基本类型数据
- PrintStream - 产生格式化输出,有print()和println()两个方法
- BufferedOutputStream - 带缓冲区的写操作,带有flush()方法用于清空缓冲区并实际执行写操作
- PrintWriter - 格式化输出,带有print()和println()方法
10. 常用的处理流的例子?
import java.io.*;
//
// 从ASCII编码的文件 test.txt 中读出所有字符
DataInputStream in = new DataInputStream(new FileInputStream("test.txt"));
//
// 从一个二进制文件 data.out 中采用缓冲的方式读取基本类型数据,已经知道这个文件按照顺序存放了一个int类型,一个long类型,四个ASCII字符
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("data.out")));
//
// 想从一个文本文件 story.txt 中按行读取字符
BufferedReader in = new BufferedReader(new FileReader("story.txt"));
//
// 向一个文件 test.data 中带缓冲写字符串,写完之后自动换行
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("test.data")));
11. 转换流?
- 转换流就是用于将字节流转换为字符流
- 常用的类:
- InputStreamReader: 将字节输入流转换成字符输入流
- OutputStreamWriter: 将字节输出流转换成字符输出流
- 例子:
import java.io.*;
public class KeyinTest {
public static void inputStreamReader(){
try (
// 将 System.in对象转换为 InputStreamReader 对象
InputStreamReader reader = new InputStreamReader(System.in);
// 将普通的 Reader 包装成 BufferedReader
BufferedReader br = new BufferedReader(reader)) {
String line = null;
// 采用循环方式逐行读取
while ((line = br.readLine()) != null) {
// 如果读取的字符串是 "exit", 则退出程序
if (line.equals("exit")) {
System.exit(1);
}
// 打印读取的内容
System.out.println("检测到输入的内容是: " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void outputStreamWriter(String path) {
try(
BufferedReader br = new BufferedReader(new FileReader(path));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))){
String data = "";
while ((data = br.readLine()) != null) {
bw.write(data);
bw.newLine();
}
}catch(Exception e) {e.printStackTrace();}
}
public static void main(String[] args) {
String path = "C:\\Users\\Desktop\\Login.html";
// inputStreamReader();
outputStreamWriter(path);
}
}
12. 重定向标准输入/输出及方法?
ava的标准输入/输出分别通过System.in和System.out来代表, 默认情况下他们分别代表键盘和显示器, 当程序 通过 System.in 来获取输入时, 实际上是从键盘读取输入, 当程序视图通过System.out 执行输出时, 程序总是 输出到屏幕; 重定向就是改变默认的输入输出情况, 例如输入重定向到从文本读取, 输出重定向为write到文本...
-
System 类里面提供下面三个重定向的标准输入/输出的方法:
- static void setErr(PrintStream err): 重定向 "标准" 错误输出流
- static void setIn(InputStream in): 重定向 "标准" 输入流
- static void setOut(PrintStream out): 重定向 "标准" 输出流
重定向标准输入从文本读取:
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;
public class RedirectIn {
public static void redirectIn(String path) {
try (FileInputStream fis = new FileInputStream(path)){
// 将标准输入重定向到 fis 输入流
System.setIn(fis);
// 使用 System.in 创建 Scanner 对象, 用于获标准输入
Scanner sc = new Scanner(System.in);
// 增加下面一行只把回车作为分隔符
sc.useDelimiter("\n");
// 判断是否还有下一个输入项
while(sc.hasNext()){
// 输出输入项
System.out.println("键盘输入的内容是: " + sc.next());
}
} catch(IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String path = "C:\\Users\\Desktop\\Login.html";
redirectIn(path);
}
}
- 重定向标准输出到写入文本, 而不是显示在屏幕
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class RedirectOut {
public static void redirectOut(String path, String str) {
try (
// 一次性创建 PrintStream 输出流
PrintStream ps = new PrintStream(new FileOutputStream(path))
) {
// 将标准输出重定向到ps输出流
System.setOut(ps);
// 向标准输出输出一个字符串
System.out.println(str);
// 向标准输出输出一个对象
System.out.println(new RedirectOut());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String str = "这是要写入的String字符串";
String path = "C:\\Users\\Desktop\\out.txt";
redirectOut(path, str);
}
}
13. RandomAccessFile(任意访问文件)?
- RandomAccessFile 既可以读取文件内容, 也可以向文件输出数据, 因为它支持自由定位文件记录指针, 所以可以跳转到文件的任意位置读写数据
- RandomAccessFile 对象包含了一个记录指针, 用于标识当前读写处的位置, 当程序新创建一个 RandomAccessFile 对象时, 该对象的文件记录指针位于文件头(也就是0处), 当读/写了n个字节后, 文件记录指针将会向后移动n个字节
- RandomAccessFile 允许自由定位文件记录指针, RandomAccessFile 可以不从开始的地方输出, 因此RandomAccessFile 可以向已存在的文件后追加内容; 如果程序需要向已存在的文件后追加内容, 则应该使用 RandomAccessFile
- RandomAccessFile 操作文件记录指针的方法:
- long getFilePointer(): 返回文件记录指针的当前位置
- void seek(long pos): 将文件记录指针定位到pos位置
- RandomAccessFile 既可以读取文件, 也可以写, 所以它既包含了完全类似于 InputStream 的三个 read() 方法, 其用法和 InputStream 的三个 read() 方法完全一样; 也包含了完全类似于 OutputStream 的三个 write() 方法 其用法和 OutputStream 的三个 write() 方法完全一样; 另外 RandomAccessFile 还包含了一些列 readXxx() 和 writeXxx() 方法来完成输入, 输出
- 创建 RandomAccessFile 对象时还需要指定一个 mode 参数, 该参数指定 RandomAccessFile 的访问模式
- "r": 只读方式打开指定文件, 如果试图对该 RandomAccessFile 执行写入方法, 将抛出 IOException 异常
- "rw": 以读, 写方式打开指定文件, 如果文件尚不存在, 则尝试创建文件
- "rws": 以读, 写方式打开指定文件, 相对于 "rw" 模式, 还要求对文件的内容或元数据的每个更新都同步写入到 底层存储设备
- "rwd": 以读, 写方式打开指定文件, 相对于 "rw" 模式, 还要求对文件内容的每个更新都同步写入到底层存储设备
14. 在文本的指定位置插入数据
// 在文件的指定位置插入文本
// 实现方法是: 找到要插入的文件位置pos, 创建临时文件, 读取pos到文件尾的数据, 输出到临时文件中
// 接着移动文件指针到pos位置, 插入指定的数据, 在读取临时文件的内容, 写入到文件中
import java.io.*;
//
public class InsertContent {
/**
* @param fileName 需要追加的文件的名字, 绝对路径
* @param pos 需要追加的位置
* @param insertContent 需要追加的内容
* @throws IOException 可能存在文件打开异常
*/
public static void insert(String fileName, long pos,
String insertContent) throws IOException {
// 通过 File 的 createTempFile() 方法创建临时文件
File tmp = File.createTempFile("tmp", null);
// 通过 File 实例调用 deleteOnExit() 方法实现退出Java虚拟机时, 删除刚才创建的临时文件
tmp.deleteOnExit();
try (
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
// 使用临时文件来保存插入点之后的数据
FileOutputStream tmpOut = new FileOutputStream(tmp);
FileInputStream tmpIn = new FileInputStream(tmp)) {
raf.seek(pos);
// -------------下面代码将插入点后的内容读入临时文件保存--------------
byte[] bbuf = new byte[64];
// 用于保存实际读取的字节数
int hasRead = 0;
// 使用循环方式读取插入点后的数据
while ((hasRead = raf.read(bbuf)) != -1) {
// 将读取的数据写入临时文件
tmpOut.write(bbuf, 0, hasRead);
}
// -------------下面代码用于插入内容--------------
// 把文件记录指针重新定位到pos位置
raf.seek(pos);
// 追加需要插入的内容
raf.write(insertContent.getBytes());
// 追加临时文件中的内容
while ((hasRead = tmpIn.read(bbuf)) > 0) {
raf.write(bbuf, 0, hasRead);
}
}
}
public static void main(String[] args) throws IOException {
insert("D:\\File\\Java\\JavaBase\\src\\xyz\\xmcs\\Main.java",
19, "// --- 这是插入的内容 --- // \r\n");
}
}
15. NIO Java的新 IO 概述?
- 新IO和传统的IO具有相同的目的, 都是用于进行输入/输出, 但新IO使用了不同的方式来处理输入/输出, 新IO采用了 内存映射文件的方式来处理输入/输出, 新IO将文件或文件的一段区域映射到内存中, 这样就可以像访问内存一样来 访问文件了, 通过这种方式来进行输入/输出比传统的输入/输出要快
- Channel(通道)和Buffer(缓冲)是新IO中的两个核心对象, Channel 是对传统的输入/输出系统的模拟, 在新IO系统 中所有的数据都需要通过通道传输; Channel 与传统的 InputStream, OutputStream最大的区别在于它提供了一个 map() 方法, 通过该 map() 方法可以直接将 "一块数据" 映射到内存中; 传统的输入/输出是面向流的处理, 新IO 则是面向块的处理
- Buffer 可以被理解成一个容器, 他的本质是一个数组, 发送到 Channel 中的所有对象都必须首先放到Buffer中, 而 从Channel 中读取的数据也必须先放到Buffer中; 此处的Buffer类似于前面介绍的 "竹筒", 但该Buffer既可以像 "竹筒" 那样一次次去Channel中取水, 也允许使用Channel直接将文件的某块数据映射成Buffer
16. Buffer?
- Buffer的内部结构就是一个数组, 它可以保存多个类型相同的数据; Buffer是一个抽象类, 最常用的子类是 ByteBuffer, 它可以在底层字节数组上进行 get/set 操作; 除此之外还有其他基本数据类型(boolean除外): CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer, DoubleBuffer
- XxxBuffer抽象类没有构造器, 只能通过下面的方法来获取Buffer对象:
- static XxxBuffer allocate(int capacity): 创建一个容量为 capacity 的 XxxBuffer 对象
- Buffer 的三个重要概念: 容量(capacity), 界限(limit), 位置(position)
- 容量(capacity): 缓冲区的容量(capacity)表示该Buffer的最大数据容量, 即最多可以存储多少数据, 缓冲区的容量 不可为负值, 创建后不能改变
- 界限(limit): 第一个不应该被读出或者写入的缓冲区位置索引, 也就是说, 位于limit后的数据既不可读, 也不可写
- 位置(position): 用于指明下一个可以被读出的或者写入的缓冲区位置索引(类似于IO流中的记录指针), 当使用Buffer 从 Channel 中读取数据时, position的值恰好等于已经读到了多少数据, 当刚刚新建了一个Buffer对象时, 其 position为0; 如果从 Channel 中读取了2个数据到Buffer时, 则 position为2, 指向Buffer中的第2个(第一个位置 索引为0)位置
17. 使用Buffer的流程?
- Buffer的主要功能就是装入数据, 然后输出数据, 开始时Buffer的position为0, limit为capacity, 程序可通过put()方法 向Buffer中放入一些数据(或者从Channel中获取一些数据), 每放入一些数据, Buffer的position相应的向后移动一些位置 当Buffer装入数据结束后, 调用Buffer的flip()方法, 该方法将limit设置为position所在位置, 并将position设为0, 这 就使得Buffer的读写指针又移到了开始位置, 也就是说, Buffer调用flip()方法之后, Buffer为输出数据做好了准备; 当 Buffer输出数据结束后, Buffer调用clear()方法, clear()方法不是清空Buffer的数据, 它仅仅将position置为0, 将 limit置为capacity, 这样为再次向Buffer中装入数据做好准备
18. Buffer 常用的方法?
- int capacity(): 返回Buffer的capacity大小
- boolean hasRemaining(): 判断当前位置(position)和界限(limit)之间是否还有元素可供处理
- int limit(): 返回Buffer的界限(limit)的位置
- Buffer limit(int newLt): 重新设置界限(limit)的值, 并返回一个具有新的limit的缓冲区对象
- Buffer mark(): 设置Buffer的mark位置, 它只能在0和位置(position)之间做mark
- int position(): 返回Buffer中的position值
- Buffer position(int newPos): 设置Buffer的position, 并返回position被修改后的Buffer对象
- int remaining(): 返回当前位置和界限之间的元素个数
- Buffer reset(): 将位置(position)转到mark所在的位置
- Buffer rewind(): 将位置(position)设置为0, 取消设置的mark
- flip(): (将limit设置为position, 再将position设为0)为从Buffer中取出数据做好准备
- clear(): (将position设为0, 将limit设置为capacity)为再次向Buffer中装入数据做好准备
- put(): 向Buffer中放入数据
- get(): 从Buffer中取出数据
19. Buffer的例子?
import java.nio.CharBuffer;
public class BufferTest {
public static void main(String[] args) {
// 通过 Buffer 的 allocate(int capacity) 方法来创建容量为capacity的Buffer对象
CharBuffer buff = CharBuffer.allocate(8);
System.out.println("capacity = " + buff.capacity());
System.out.println("limit = " + buff.limit());
System.out.println("position = " + buff.position());
// 通过 put() 方法放入元素
buff.put('a');
buff.put('b');
buff.put('c');
// 放入元素后, position 的位置也会随之往后移
System.out.println("加入三个元素后, position = " + buff.position());
// 调用flip()方法, 将limit移动到position, 将position位置移动到0, 为读取数据做好准备
buff.flip();
System.out.println("执行flip()方法后, limit = " + buff.limit());
System.out.println("执行flip()方法后, position = " + buff.position());
// 取出第一个元素
System.out.println("取出第一个元素(position = 0): " + buff.get());
System.out.println("取出第一个元素后, position = " + buff.position());
// 调用clear()方法将position移动到0, 将limit移动到capacity的位置, 为装入数据做好准备
buff.clear();
System.out.println("执行clear()后, limit = " + buff.limit());
System.out.println("执行clear()方法后, position = " + buff.position());
System.out.println("执行clear()后, 缓冲区内容并没有被清除: "
+ "第三个元素为: " + buff.get(2));
System.out.println("执行绝对读取后, position = " + buff.position());
}
}
20. Channel?
- Channel接口可以直接将指定文件的部分或全部直接映射成Buffer
- 程序不能直接访问 Channel中的数据, 包括读取, 写入都不行, Channel 只能和 Buffer 交互; 如果要从 Channel 中 取得数据, 必须先用 Buffer 从 Channel 中取出一些数据, 然后让程序从Buffer中取出这些数据; 如果要将程序中的 数据写入 Channel, 也要先让程序将数据放入 Buffer 中, 程序再将 Buffer 里的数据写入 Channel 中
- Channel 接口的实现类:
- Pipe.SinkChannel, Pipe.SourceChannel: 这两个实现类用于支持线程之间通信的管道 Channel
- ServerSocketChannel, SocketChannel: 是用于支持TCP网络通信的Channel
- DatagramChannel: 是用于支持UDP网络通信的 Channel
- FileChannel: 是用于文件访问的 Channel
- 所有的 Channel 通过传统的节点 InputStream, OutputStream 的 getChannel() 方法来返回
- Channel 中最常用的三类方法是 map(), read(), write()
- map() 用于将 Channel 对应的部分或全部数据映射成ByteBuffer
- read() 用于从Buffer中读取数据
- write() 向Buffer中写入数据
- map() 方法的方法签名为: MappedByteBuffer map(FileChannel.MapMode mode, long position, long size): 第一个 参数执行映射时的模式, 分别有只读, 读写模式; 第二个参数, 第三个参数用于控制将 Channel 的那些数据映射成ByteBuffer
- 例子:
// Channel 通过 "少拿勤跑" 的方式映射数据
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
//
public class ReadFile {
public static void main(String[] args) throws IOException {
try (
// 创建文件输入流
FileInputStream fis = new FileInputStream(
"D:\\File\\Java\\JavaBase\\src\\xyz\\xmcs\\CrazyJava\\IO\\ReadFile.java");
// 通过文件输入流创建一个FileChannel对象
FileChannel fc = fis.getChannel()) {
// 定义一个ByteBuffer对象, 用于重复取水
ByteBuffer bbuff = ByteBuffer.allocate(256);
// 将 FileChannel 中的数据放入 ByteBuffer 中
while (fc.read(bbuff) != -1) {
// 锁定Buffer的空白区
bbuff.flip();
// 创建 Charset 对象
Charset charset = Charset.forName("UTF-8");
// 创建解码器 (CharsetDecoder) 对象
CharsetDecoder decoder = charset.newDecoder();
// 将 ByteBuffer 的内容转码
CharBuffer cbuff = decoder.decode(bbuff);
System.out.print(cbuff);
// 将 Buffer 初始化, 为下一次读取数据做好准备
bbuff.clear();
}
}
}
}
21. Path ?
- Path 接口代表一个平台无关的平台操作
- 例子
// Path 接口的功能和方法
import java.nio.file.Path;
import java.nio.file.Paths;
//
public class PathTest {
public static void main(String[] args) throws Exception {
// 以当前路径来创建Path对象
Path path = Paths.get(".");
System.out.println("path 里包含的路径数量: " + path.getNameCount());
// 获取path对应的绝对路径
Path absolutePath = path.toAbsolutePath();
System.out.println(absolutePath);
// 获取绝对路径的根路径
System.out.println("absolutePath 的根路径: " + absolutePath.getRoot());
// 获取绝对路径所包含的路径数量
System.out.println("absolutePath 里包含的路径数量: " + absolutePath.getNameCount());
System.out.println(absolutePath.getName(0));
// 以多个String来构建Path对象
Path path2 = Paths.get("D:", "Books", "Java");
System.out.println(path2);
}
}
22. Files ?
- Files 包含了大量静态的工具来操作文件
- 例子
// Files 操作文件工具类
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
//
public class FilesTest {
public static void main(String[] args) throws Exception {
String FileTestPath = "D:\\File\\Java\\JavaBase\\src\\xyz\\xmcs\\CrazyJava\\IO\\FilesTest.java";
// 复制文件
Files.copy(Paths.get(FileTestPath), new FileOutputStream("a.txt"));
// 判断 FilesTest.java 文件是否为隐藏文件
System.out.println("FilesTest.java 是否为隐藏文件: "
+ Files.isHidden(Paths.get(FileTestPath)));
// 一次性读取 FilesTest.j所有行
List<String> lines = Files.readAllLines(Paths.get(FileTestPath), Charset.forName("UTf-8"));
System.out.println(lines);
// 判断指定文件的大小
System.out.println("FilesTest.Java 的大小为: "
+ Files.size(Paths.get(FileTestPath)));
List<String> poem = new ArrayList<>();
poem.add("水晶潭底银鱼跃");
poem.add("清风徐来碧竿横");
// 直接将多个字符串内容写入指定文件中
Files.write(Paths.get("poem.txt"), poem, Charset.forName("UTF-8"));
// 使用Java8新增的 Stream API 列出当前目录下所有文件和子目录
Files.list(Paths.get(".")).forEach(path -> System.out.println(path));
// 使用Java8 新增的API读取文件内容
Files.lines(Paths.get(FileTestPath), Charset.forName("UTF-8")).forEach(line -> System.out.println(line));
FileStore cStore = Files.getFileStore(Paths.get("C:"));
// 判断 C盘的总空间, 可用空间
System.out.println("C盘的共有空间: " + cStore.getTotalSpace());
System.out.println("C盘的可用空间: " + cStore.getUsableSpace());
}
}